Django CBV: готовые классы на примере Generic Base View
Смотрим CBV под капотом и как подключать классы к URL-маршрутам, за что отвечают методы setup() и dispatch() и как использовать Generic Views
В статье Django CBV: что такое Class-Based Views мы разобрались в каких случаях полезно использовать CBV, теперь же посмотрим что для нас приготовили разработчики Django, чтобы облегчить написание кода.
В Django имеется целая серия готовых типов классов views - представлений, для удобства они собраны на сайте https://ccbv.co.uk/ .
Все начинается с обычного Python класса с парой хитростей - View .
Этот базовый класс простой и универсальный, его фишка в том, что он содержит методы (функции), которые далее по цепочке наследуют другие готовые классы.
Его единственное предназначение это принять запрос и вернуть ответ, а так же если указано, он перенаправит запрос на необходимый метод (GET, POST, PUT, DELETE).
URL-диспетчер ← вызывает функцию из as_view()
↓
as_view() ← создаёт экземпляр класса - каждый запрос новый объект
↓
setup() ← устанавливает request, args, kwargs
↓
dispatch() ← смотрит на request.method
↓
get() / post() ← вызывает нужный метод
/ put() / delete()
↓
HttpResponse ← возвращает ответсхема работы View класса
В urls.py django вызывает функции, а не классы, потому требуется прописывать название класса с методом .as_view() .
Этот метод для каждого вызова создаёт новый экземпляр класса и возвращает функцию view.
path("about/", AboutView.as_view(), name="about")пример пути django в файле urls.py у CBV
Setup записывает данные запроса в экземпляр объекта, чтобы они были доступны через self в любом методе класса.
def setup(self, request, *args, **kwargs):
if hasattr(self, "get") and not hasattr(self, "head"):
self.head = self.get
self.request = request
self.args = args
self.kwargs = kwargsМетод setup класса View из кода Django
Метод можно переопределить, чтобы записать свои данные внутрь, которые будут использованы в dispatch или далее.
class ProjectView(View):
def setup(self, request, *args, **kwargs):
super().setup(request, *args, **kwargs) # чтобы сохранить изначальные request, args и kwargs
self.project = get_object_or_404(Project, slug=kwargs["slug"])Пример переопределения setup в django CBV
Dispatch это диспетчер, он по условию передает запрос дальше или останавливает его, в частности отдает 405 ошибку если одно из этих условий отрицательно:
метод указан в http_method_names
в классе присутствует метод из запроса (пример: get, post, put, delete, options, head)
class NoteView(View):
http_method_names = ["get", "post"] # остальное: 405
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return JsonResponse({"error": "Требуется вход"}, status=401)
return super().dispatch(request, *args, **kwargs)
def get(self, request, *args, **kwargs):
return JsonResponse({"user": request.user.username})
def post(self, request, *args, **kwargs):
return JsonResponse({"ok": True}, status=201)пример с http_method_names и dispatch в Django CBV
В примере выше запросы кроме get и post выдадут 405 ошибку.
Методом dispatch можно проверить права доступа до обращения к данным в представлении - view, это может сыграть важную роль в безопасности, в чистоте кода и в экономии ресурсов машины.
class OwnerOnlyMixin:
def dispatch(self, request, *args, **kwargs):
if not request.user.is_authenticated:
return redirect("login")
return super().dispatch(request, *args, **kwargs)пример кода проверки прав доступа через mixin с dispatch в django CBV
Также методом dispatch можно описать логику до и после обработки представления.
def dispatch(self, request, *args, **kwargs):
start = time.monotonic()
response = super().dispatch(request, *args, **kwargs)
response["X-Elapsed"] = f"{time.monotonic() - start:.3f}"
return responseпример кода dispatch в django CBV для подсчета затраченного времени
При помощи dispatch можно перенаправить запрос на иной обработчик по условию или пропустить дальше.
def dispatch(self, request, *args, **kwargs):
if request.headers.get("X-Requested-With") == "XMLHttpRequest":
return self.ajax(request, *args, **kwargs)
return super().dispatch(request, *args, **kwargs)пример кода dispatch в django cbv для перенаправления запроса
Общие базовые представления (Generic Base View) это основные классы, которые зачастую являются основой для более сложных представлений (views).
В их число входят классы View (рассмотренный выше), TemplateView и RedirectView.
Многие дочерние представления - View обретают свою уникальность благодаря миксинам, напримерclass TemplateView(TemplateResponseMixin, ContextMixin, View).
Миксины пишутся с левой стороны от основного класса, так как обработка происходит слева направо.
TemplateView предназначен для страниц, которым нужно просто отобразить шаблон, подходит например для страницы "О нас", где просто текст.
Но по необходимости, можно вывести и данные через метод get_context_data(), а так же можно передать параметр через ссылку (url).
# views.py
class PageView(TemplateView):
template_name = "pages/page.html" # достаточно этой строки
def get_context_data(self, **kwargs):
# добавляем если хочется встроить свои данные
# или обработать параметр из ссылки
context = super().get_context_data(**kwargs)
page = get_object_or_404(Page, slug=kwargs["slug"])
context["page"] = page
context["title"] = page.title
context["posts"] = Post.objects.all()
return context
# urls.py
path("pages/<slug:slug>/", PageView.as_view(), name="page")
# pages/page.html
<h1>{{ title }}</h1>
{{ page.content }}
{% for post in posts %}
<p>{{ post.title }}</p>
{% endfor %}пример TemplateView с get_context_data в Django CBV
Для простых страниц типа "О нас" или "Контакты" где не требуются данные из базы данных, а шаблон уже готов, можно использовать одностроковую версию сразу в urls.py.
path("about/", TemplateView.as_view(template_name="about.html"), name="about")одностроковое использование TemplateView в Django CBV
RedirectView используется для перенаправления запроса пользователя.
# views.py
class OldPageView(RedirectView):
url = "https://new-site.com"
# urls.py
urlpatterns = [
path("old-page/", OldPageView.as_view(), name="old-page"),
]Пример RedirectView в Django CBV
Возможно использовать и вариант в 1 строку.
path("blog/<int:pk>/", RedirectView.as_view(url="/posts/%(pk)d/"))Пример в одну строку RedirectView в Django CBV
Если у вас остались вопросы по django базовым классовым представлениям View можете обратиться за консультацией к программисту.





