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

⏱ 20 мин · 🧩 заданий: 5

Функции и классы

До сих пор view были функциями. Django также позволяет писать представления на основе классов (class-based views, CBV). Их преимущества:

  • код для разных HTTP-методов разделён по методам класса (get, post), а не по if;
  • можно наследоваться и переопределять части поведения;
  • миксины добавляют функции (например, «только для вошедших»);
  • обобщённые представления (generic views) решают типовые задачи — список, детальная страница, создание — почти без кода.

Базовый класс View

from django.http import HttpResponse
from django.views import View


class HelloView(View):
    def get(self, request):
        return HttpResponse("Привет от GET")

    def post(self, request):
        return HttpResponse("Привет от POST")
path("hello/", HelloView.as_view(), name="hello")

as_view() превращает класс в функцию, которую понимает диспетчер URL. На каждый запрос создаётся новый экземпляр, метод dispatch() вызывает get() или post() в зависимости от метода запроса, а на неподдерживаемые методы отвечает 405.

TemplateView

Для страниц, которым нужен только шаблон:

from django.views.generic import TemplateView


class AboutView(TemplateView):
    template_name = "about.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["posts_count"] = Post.published.count()
        return context

Или прямо в urls.py: path("about/", TemplateView.as_view(template_name="about.html")).

ListView для блога

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"
Атрибут Значение
model = Post Модель (альтернатива queryset, тогда берётся Post.objects.all())
queryset Свой набор объектов
context_object_name Имя списка в шаблоне (по умолчанию object_list и post_list)
paginate_by Объектов на странице
template_name Шаблон (по умолчанию blog/post_list.html)
ordering Сортировка

Маршрут:

urlpatterns = [
    path("", views.PostListView.as_view(), name="post_list"),
    ...
]

Пагинация в ListView

ListView передаёт в шаблон объект страницы как page_obj. Обновим list.html:

{% include "pagination.html" with page=page_obj %}

Неверный номер страницы ListView обрабатывает сам: ?page=abc или ?page=999 дадут 404.

Динамический набор: get_queryset

Если набор зависит от запроса — переопределите метод:

class PostListView(ListView):
    paginate_by = 3
    context_object_name = "posts"
    template_name = "blog/post/list.html"

    def get_queryset(self):
        qs = Post.published.select_related("author")
        q = self.request.GET.get("q")
        if q:
            qs = qs.filter(title__icontains=q)
        return qs

Внутри CBV доступны self.request, self.args, self.kwargs (параметры из URL).

DetailView

Для одной записи — DetailView:

from django.views.generic import DetailView


class PostDetailView(DetailView):
    model = Post
    template_name = "blog/post/detail.html"
    context_object_name = "post"

По умолчанию ищет объект по pk или slug из URL. Наш адрес с датой сложнее, поэтому для блога оставим функцию post_detail — смешивать функции и классы в одном проекте нормально. Подробно DetailView, CreateView, UpdateView и миксины разберём в проекте «Сайт статей».

Функции или классы?

Функции Классы
Явный, линейный код Меньше кода для типовых задач
Проще читать новичку Наследование и миксины
Удобно для нестандартной логики Нужно знать, какие методы переопределять

Оба подхода официально поддерживаются. Хорошее правило: типовые CRUD-страницы — generic views, нестандартная логика — функции.

Итог

  • CBV разделяют обработку HTTP-методов по методам класса, подключаются через as_view().
  • TemplateView — страница с шаблоном, ListView — список с пагинацией, DetailView — одна запись.
  • get_queryset() и get_context_data() — главные точки расширения.
  • ListView передаёт страницу как page_obj.

Практика решено 0 из 5

Вы не вошли — ответы проверяются, но прогресс не сохранится. Войти или зарегистрироваться.
Задание 1 Написать код

Перепишите список постов на ListView: класс PostListView, набор — Post.published.all(), имя переменной в шаблоне — posts, по 3 на странице, шаблон — blog/post/list.html.

Задание 2 Написать код

Подключите PostListView к маршруту "" с именем post_list.

Задание 3 Один вариант ответа

Как ListView с paginate_by передаёт страницу в шаблон?

Задание 4 Один вариант ответа

Какой шаблон по умолчанию ищет ListView для модели Post из приложения blog?

Задание 5 Несколько вариантов

Какие методы обработчиков HTTP можно определить в классе-наследнике View?

Войдите, чтобы отмечать пройденные уроки.