Представления на основе классов
CBV изнутри
В блоге мы использовали ListView, почти не заглядывая внутрь. В этом проекте почти все страницы будут на классах, поэтому разберёмся, как они устроены.
as_view()
path("", ArticleListView.as_view(), name="home")
as_view() — classmethod, который возвращает функцию. На каждый запрос эта функция:
- создаёт новый экземпляр класса (поэтому хранить состояние в
selfбезопасно); - вызывает
setup(request, *args, **kwargs)— сохраняетself.request,self.args,self.kwargs; - вызывает
dispatch(), который по методу запроса вызываетget(),post()и т. д., или отвечает 405.
Атрибуты можно передать прямо в as_view(): TemplateView.as_view(template_name="about.html").
Иерархия generic views
| Класс | Назначение |
|---|---|
View |
База: dispatch, методы HTTP |
TemplateView |
Отрисовать шаблон |
RedirectView |
Перенаправить |
ListView |
Список объектов, пагинация |
DetailView |
Один объект по pk или slug |
FormView |
Форма без модели |
CreateView |
Создание объекта через ModelForm |
UpdateView |
Редактирование |
DeleteView |
Удаление с подтверждением |
Каждый собран из миксинов: например, ListView = MultipleObjectTemplateResponseMixin + BaseListView (= MultipleObjectMixin + View). Подробную карту всех атрибутов и методов удобно смотреть на сайте ccbv.co.uk.
Жизненный цикл ListView
get()
├── self.object_list = get_queryset()
├── context = get_context_data(object_list=...)
│ ├── paginate_queryset() (если paginate_by)
│ └── context_object_name
└── render_to_response(context)
└── get_template_names()
Главные точки расширения
| Метод / атрибут | Что меняет |
|---|---|
model, queryset |
Откуда брать объекты |
get_queryset() |
Динамический набор (фильтр по URL, пользователю) |
get_context_data() |
Дополнительные переменные в шаблоне |
template_name, get_template_names() |
Шаблон |
context_object_name |
Имя объекта/списка в шаблоне |
paginate_by |
Пагинация |
get_object() |
Как найти объект (DetailView и др.) |
dispatch() |
Логика до обработки (проверки доступа) |
Пример — главная страница сайта статей:
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article
template_name = "blog/articles_list.html"
context_object_name = "articles"
paginate_by = 6
def get_queryset(self):
return Article.custom.all()
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Главная страница"
return context
Всегда вызывайте super() в get_context_data — иначе потеряете контекст, который собирают родительские классы (список объектов, пагинацию).
Миксины
Миксин — маленький класс с одной функцией, который «подмешивают» к представлению:
class TitleMixin:
title = None
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = self.title
return context
class ArticleListView(TitleMixin, ListView):
title = "Главная страница"
...
Миксины ставят левее базового представления: Python ищет методы слева направо (MRO), а super() передаёт управление дальше по цепочке. Встроенные миксины Django: LoginRequiredMixin, PermissionRequiredMixin, UserPassesTestMixin, SuccessMessageMixin. Свои миксины напишем в отдельном уроке.
Итог
as_view()→ новый экземпляр →setup()→dispatch()→get()/post().- Generic views собраны из миксинов; главные точки расширения —
get_queryset,get_context_data,get_object,dispatch. - В переопределённых методах вызывайте
super(). - Миксины добавляют функциональность через множественное наследование и ставятся слева.
Практика решено 0 из 5
Расставьте этапы обработки запроса представлением-классом (ListView).
-
dispatch()выбирает метод по HTTP-методу —get() -
Создаётся экземпляр класса, вызывается
setup()(сохраняет request, args, kwargs) -
get_context_data()собирает контекст -
render_to_response()рендеритget_template_names() -
get()вызываетget_queryset() -
as_view()создаёт функцию, которую вызывает диспетчер URL
Какой метод переопределить, чтобы добавить в шаблон дополнительную переменную title?
Переопределите get_context_data во view, добавив в контекст title со значением "Главная страница".
Не забудьте вызвать родительский метод.
class ArticleListView(ListView):
model = Article
template_name = "blog/articles_list.html"
context_object_name = "articles"
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context["title"] = "Главная страница"
return context
Какие классы — это generic views Django для работы с объектами?
Что такое миксин (mixin)?
Войдите, чтобы отмечать пройденные уроки.