Разработка представлений на основе классов
Мы разработали приложение blog, используя представления на основе функций. Такие представления просты и мощны, но Django также позволяет разрабатывать представления с использованием классов.
Представления на основе классов являются альтернативным функциям способом реализации представлений как объектов Python.
Поскольку представление – это функция, которая принимает веб-запрос и возвращает веб-ответ, то существует возможность определять представления как методы класса.
Django предоставляет базовые классы-представления, которые можно использовать для реализации своих собственных представлений. Все они наследуют от класса View, который служит для диспетчеризации HTTP-методов и других распространенных функциональностей.
Зачем использовать представления на основе классов
Представления на основе классов обладают некоторыми преимуществами по сравнению с представлениями на основе функций, которые удобны для конкретных случаев использования.
Представления на основе классов позволяют:
-
организовывать исходный код, относящийся к HTTP-методам, таким как GET, POST или PUT, в отдельные методы, не используя ветвление по условию;
-
использовать множественное наследование, чтобы создавать реиспользуемые классы-представления (также именуемые примесями, примесными классами или миксинами).
Использование представления на основе класса для отображения списка постов
В целях понимания того, как писать представления на основе классов, мы создадим новое представление на основе класса, эквивалентное представлению post_list.
Мы создадим класс, который будет наследовать от предлагаемого веб-фреймворком Django типового представления ListView. Представление ListView позволяет перечислять объекты любого типа.
Отредактируйте файл views.py приложения blog, добавив следующий ниже исходный код:
from django.views.generic import ListView
class PostListView(ListView):
"""
Альтернативное представление списка постов
"""
queryset = Post.published.all()
context_object_name = 'posts'
paginate_by = 3
template_name = 'blog/post/list.html'
Представление PostListView похоже на разработанное ранее представление post_list.
Мы имплементировали представление, основанное на классе, которое наследует от класса ListView, при этом определив его со следующими атрибутами:
-
атрибут
querysetиспользуется для того, чтобы иметь конкретно-прикладной набор запросов QuerySet, не извлекая все объекты. Вместо определения атрибутаquerysetмы могли бы указатьmodel=Post, и Django сформировал бы для нас типовой набор запросовPost.objects.all(); -
контекстная переменная
postsиспользуется для результатов запроса. Если не указано имя контекстного объектаcontext_object_name, то по умолчанию используется переменнаяobject_list; -
в атрибуте
paginate_byзадается постраничная разбивка результатов с возвратом трех объектов на страницу; -
конкретно-прикладной шаблон используется для прорисовки страницы шаблоном
template_name. Если шаблон не задан, то по умолчаниюListViewбудет использоватьblog/post_list.html.
Теперь отредактируйте файл urls.py приложения blog, закомментировав предыдущий шаблон URL-адреса post_list и добавив новый шаблон URL-адреса, используя класс PostListView, как показано ниже:
urlpatterns = [
# представления поста
# path('', views.post_list, name='post_list'),
path('', views.PostListView.as_view(), name='post_list'),
path('<int:year>/<int:month>/<int:day>/<slug:post>/',
views.post_detail,
name='post_detail'),
]
Для того чтобы постраничная разбивка продолжала работать, необходимо использовать правильный объект страницы, который передается в шаблон.
Встроенное в Django типовое представление ListView передает запрошенную страницу в переменную с именем page_obj.
В связи с этим необходимо соответствующим образом отредактировать шаблон post/list.html, чтобы вставить разбивщика, используя правильную переменную, как показано ниже:
{% extends "blog/base.html" %}
{% block title %}My Blog{% endblock %}
{% block content %}
<h1>My Blog</h1>
{% for post in posts %}
<h2>
<a href="{{ post.get_absolute_url }}">
{{ post.title }}
</a>
</h2>
<p class="date">
Published {{ post.publish }} by {{ post.author }}
</p>
{{ post.body|truncatewords:30|linebreaks }}
{% endfor %}
{% include "pagination.html" with page=page_obj %}
{% endblock %}
Пройдите по URL-адресу http://127.0.0.1:8000/blog/ в своем браузере и проверьте, чтобы ссылки с постраничной разбивкой работали должным образом.
Поведение постранично разбитых ссылок должно быть таким же, как и в предыдущем представлении post_list.
Обработка исключений в этом случае немного отличается.
Если попытаться загрузить страницу вне диапазона или передать не целочисленное значение в параметре page, то представление вернет HTTP-ответ с кодом состояния, равным 404 (Страница не найдена), как показано ниже:
Обработка исключений, которая возвращает HTTP-ответ с кодом состояния 404, предусмотрена типовым представлением ListView. Это простой пример того, как писать представления на основе классов.
Введение в представления на основе классов можно почитать на странице https://docs.djangoproject.com/en/4.2/topics/class-based-views/intro/.