Django 5 для начинающих

Прогресс по курсу:  9/1004

5.5 Разработка представлений списка и детальной информации
2 из 5 шагов пройдено
0 из 9 баллов  получено

Разработка представлений списка и детальной информации

Теперь, когда вы понимаете, как использовать ORM-преобразователь, вы готовы к разработке представлений приложения blog.

Представление Django – это просто функция Python, которая получает веб-запрос и возвращает веб-ответ. Вся логика желаемого ответа находится внутри функции-представления.

Сначала в своем приложении нужно создать функции-представления, затем по каждому представлению сформировать шаблон URL-адреса и, наконец, создать шаблоны HTML, чтобы прорисовывать сгенерированные представлениями данные.

Каждое представление будет прорисовывать шаблон, передавая ему переменные, и возвращать HTTP-ответ с прорисованным результатом.

 

Создание представлений списка постов и детальной информации о посте

Давайте начнем с создания представления списка постов на странице.
Отредактируйте файл views.py приложения blog, придав ему следующий вид:

from django.shortcuts import render
from .models import Post


def post_list(request):
    posts = Post.published.all()
    return render(request,
                  'blog/post/list.html',
                  {'posts': posts})

Это ваше самое первое представление Django. Представление post_list принимает объект request в качестве единственного параметра. Указанный параметр необходим для всех функций-представлений.

В данном представлении извлекаются все посты со статусом PUBLISHED, используя менеджер published, который мы создали ранее.

Наконец, мы используем функцию сокращенного доступа render(), предоставляемую Django, чтобы прорисовать список постов заданным шаблоном.

Указанная функция принимает объект request, путь к шаблону и контекстные переменные, чтобы прорисовать данный шаблон.

Она возвращает объект HttpResponse с прорисованным текстом (обычно исходным кодом HTML).

Функция сокращенного доступа render() учитывает контекст запроса, поэтому любая переменная, установленная процессорами контекста шаблона, доступна данному шаблону.

Процессоры контекста шаблона - это просто вызываемые объекты (функции, методы и классы), которые назначают контекст переменным.

Давайте создадим второе представление одиночного поста на странице.
Добавьте следующую ниже функцию в файл views.py:

# импорт....
from django.http import Http404  # новый импорт


#### функция post_list


def post_detail(request, id): 
    try:
        post = Post.published.get(id=id)

    except Post.DoesNotExist:
        raise Http404("No Post found.")

    return render(request,
                  'blog/post/detail.html',
                  {'post': post})

Это представление детальной информации о посте.

Указанное представление принимает аргумент id поста. Здесь мы пытаемся извлечь объект Post с заданным id, через наш кастомный менеджер, который выводит опубликованные записи. И он же в свою очередь  вызывает метод get() стандартного менеджера objects.

Мы создаем исключение Http404, чтобы вернуть ошибку HTTP с кодом состояния, равным 404, если возникает исключение DoesNotExist, то есть модель не существует, поскольку результат не найден.

Наконец, мы используем функцию сокращенного доступа render(), чтобы прорисовать извлеченный пост с использованием шаблона.

 

Применение функции сокращенного доступа get_object_or_404()

Django предоставляет функцию сокращенного доступа для вызова метода get() в заданном модельном менеджере и вызова исключения Http404 вместо исключения DoesNotExist, когда объект не найден.

Отредактируйте файл views.py, импортировав функцию сокращенного доступа get_object_or_404 и изменив представление post_detail, как показано ниже:

from .models import Post
from django.shortcuts import render, get_object_or_404


def post_list(request):
    posts = Post.published.all()
    return render(request,
                  'blog/post/list.html',
                  {'posts': posts})


def post_detail(request, id):
    post = get_object_or_404(Post,
                             id=id, status=Post.Status.PUBLISHED)
    return render(request,
                  'blog/post/detail.html',
                  {'post': post})

Теперь в представлении детальной информации о посте используется функция сокращенного доступа get_object_or_404(), чтобы извлекать желаемый пост.

Указанная функция извлекает объект, соответствующий переданным параметрам, либо исключение HTTP с кодом состояния, равным 404(не найдено), если объект не найден.


  • Комментариев
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий
Комментарий закреплён

Понравилась задача, тест или урок? Поставьте лайк, поддержите курс. Ваша поддержка очень важна для нас.

На этом фрагменте, как будто забыли вписать render(...). Или я ошибаюсь?

@Кирилл_Смирнов, Да, все верно говорите.

Извиняемся за такую ошибку, в момент редактирования данной лекции эта строчка куда-то пропала))

@Илья_Перминов, Все отлично! На то мы первопроходцы и нужны!)
P.S Курс пока только радует

@Кирилл_Смирнов, Спасибо, нам очень приятно это слышать!

А мы можем кастомизировать вывод при срабатывании ошибки в get_object_or_404?

@Павел_Кирсанов, нет:

def get_object_or_404(klass, *args, **kwargs):
...
    try:
        return queryset.get(*args, **kwargs)
    except queryset.model.DoesNotExist:
        raise Http404(
            "No %s matches the given query." % queryset.model._meta.object_name
        )

https://github.com/django/django/blob/8fd953f28abc95aee2e2f59c94d8c58af0d792d7/django/shortcuts.py#L85

@Дмитрий_Селезнев, а правильно ли понимаю, что в кастомизации и нет необходимости, достаточно прописать хендлер на 404 и обрабатывать уже там, такая возможность у нас остается?

@Нарбеков_Марсель, абсолютно верно, так и нужно делать.

@Дмитрий_Селезнев, понял, большое спасибо!

Имена функций post_list, post_detail это произвольные имена или какие-то зарезервированные?

@Дмитрий_Чекмасов, произвольные, написаны так, чтобы было понимание, что выполняет данная функция представления.

Изменен Илья Перминов

Указанная функция извлекает объект, соответствующий переданным параметрам, либо исключение HTTP с кодом состояния, равным 404(не найдено), если объект не найден.

Исключение тут передаётся в переменной post, то есть ошибка будет не на весь шаблон detail.html а только там, где используется переменная post? Или когда в одной из переменных шаблона ошибка падает весь шаблон?  

@Георгий_Тимофеев, 404 ошибка, это код ответа сервера. То есть будет вывод стандартного шаблона 404 ошибки. Можете посмотреть как ее можно обрабатывать своим шаблоном.

@Илья_Перминов, я тут больше про то, что без get_object_or_404 мы явно райзим исключение в функции-представлении, а с этой функцией получается просто передаем ошибку в шаблон в качестве переменной, и он уже там дальше сам разберётся. 

Или как вариант get_object_or_404 не доходит до return и если ошибка - сразу тоже возбуждает исключение.. тогда все встает на свои места. Т.е. код ответа сервера 404 не сохраняется в переменной.

@Георгий_Тимофеев, get_object_or_404 не доходит до return в случае ошибки. Вот смотрите, код ниже:

def my_view(request):
    obj = get_object_or_404(MyModel, pk=1)

Он эквивалентен следующему коду:

def my_view(request):
    try:
        obj = MyModel.objects.get(pk=1)
    except MyModel.DoesNotExist:
        raise Http404("No MyModel matches the given query.")

@Илья_Перминов, теперь понял, спасибо)

видимо тут в первом случае должен стоять objects:

@Ilia_Boiarintsev, или по логике мы можем просматривать только опубликованные посты?

@Ilia_Boiarintsev, Мы в модель добавили менеджер, который у каждого запроса проверяет статус(опубликовано или нет), когда мы вызываем как  Post.published. А когда мы делаем запрос Post.published.get(), то вызывается стандартный метод get у object, но к запросу добавляется проверка статуса публикации. Добавили в лекцию уточнение по этому моменту.

@Илья_Перминов, все, понял логику