В предыдущей статье мы рассмотрели, почему нужны класс основанные представления (CBV) в Django и какие преимущества они имеют по сравнению с функцией основанными представлениями (FBV). В этом посте мы подробно рассмотрим базовый класс представления Django, который можно считать основой всех CBV.
“Чтобы правильно понять CBV, важно сначала понять, как работает django.views.View и какую структуру она имеет.”
1. Что такое класс представления Django?
Все класс основанные представления Django используют класс django.views.View
в следующем формате.
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
# Логика обработки GET запроса
...
def post(self, request, *args, **kwargs):
# Логика обработки POST запроса
...
Особенности класса View
-
Разделение методов по HTTP методам
Когда поступает запрос, Django автоматически вызывает соответствующие функции для методовget()
,post()
,put()
,delete()
через внутренний методdispatch()
.- Не нужно использовать такие условные выражения, как “if request.method == 'GET': … else: …”, что делает структуру кода более чистой.
-
Наследование и расширяемость
Можно создать несколько дочерних представлений, унаследовав класс представления, и максимально использовать повторное использование кода, положив общую логику в родительский класс и индивидуальную логику в дочерних классах.
2. Основная структура и принцип работы класса View
Самый простой пример
# views.py
from django.http import HttpResponse
from django.views import View
class HelloCBV(View):
def get(self, request, *args, **kwargs):
return HttpResponse("Привет, CBV!")
-
get()
метод: выполняется, когда браузер отправляет GET запрос (ввод URL в адресной строке, клик по ссылке и т.д.). -
HttpResponse("Привет, CBV!")
: создается и возвращается ответ в текстовом формате.
Подключение к urls.py
# urls.py
from django.urls import path
from .views import HelloCBV
urlpatterns = [
path('hello/', HelloCBV.as_view(), name='hello_cbv'),
]
-
.as_view()
метод преобразует CBV в форму, которую Django может понять. -
Когда шаблон URL связан, при поступлении GET запроса на
http://example.com/hello/
вызывается методget()
HelloCBV
.
3. Использование класса View и примеры из практики
Случаи, подобные вышеупомянутому, где просто “возвращается одна строка” довольно редки. Обычно в реальных проектах часто выполняются JSON ответы, отрисовка шаблонов или выполнение запросов к базе данных. Здесь мы посмотрим на примеры JSON ответов и отрисовки шаблонов.
3.1 Пример обработки JSON ответа
# views.py
from django.http import JsonResponse
from django.views import View
class UserDataView(View):
def get(self, request, *args, **kwargs):
# Например, предположим, что мы получаем user_id через GET параметры
user_id = request.GET.get('user_id', None)
if not user_id:
return JsonResponse({'error': 'Не предоставлен user_id'}, status=400)
# На самом деле выполняем запрос к БД
user_data = {
'id': user_id,
'name': f'User_{user_id}',
'role': 'admin'
}
return JsonResponse(user_data, status=200)
def post(self, request, *args, **kwargs):
# Можно анализировать JSON или form данные из тела POST запроса.
# Доступны request.POST, request.body, request.FILES и т.д.
# В реальном сервисе логика сохранения в БД после анализа JSON
new_user_data = {
'id': 123,
'name': 'NewUser',
'role': 'member'
}
return JsonResponse(new_user_data, status=201)
-
JsonResponse
: инструмент для удобного создания JSON ответов в Django. -
request.GET
,request.POST
: можно получить GET/POST параметры из объекта HttpRequest Django. -
На практике данные обрабатываются более структурировано, связывая с моделью БД или используя Serializer.
3.2 Пример отрисовки шаблона
# views.py
from django.shortcuts import render
from django.views import View
class GreetingView(View):
def get(self, request, *args, **kwargs):
context = {
'title': 'Добро пожаловать на мой сайт',
'greeting': 'Привет, это GreetingView!'
}
return render(request, 'greeting.html', context)
<!-- templates/greeting.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ greeting }}</h1>
</body>
</html>
-
render()
функция ищет файл шаблона (greeting.html
) и возвращает отрисованный HTML в формеHttpResponse
. -
Таким образом, отрисовка шаблона внутри CBV также может быть выполнена просто.
4. Расширяемость и повторное использование класса View
Одной из самых больших причин полезности класса View является “повторное использование кода”. По мере роста проекта более целесообразно помещать общую логику (например, логгирование, проверка аутентификации, обработка общих данных и т.д.) в родительский класс и наследовать ее в дочерних классах.
4.1 Помещение общей логики в родительский класс
# views.py
from django.http import JsonResponse
from django.views import View
class BaseLoggingView(View):
def dispatch(self, request, *args, **kwargs):
# Выполнение общей логики для всех запросов (GET/POST и т.д.)
print(f"[Log] {request.method} request at {request.path}")
return super().dispatch(request, *args, **kwargs)
class ChildLoggingView(BaseLoggingView):
def get(self, request, *args, **kwargs):
data = {'message': 'GET ответ от дочернего класса'}
return JsonResponse(data)
def post(self, request, *args, **kwargs):
data = {'message': 'POST ответ от дочернего класса'}
return JsonResponse(data)
-
dispatch()
метод: основной метод, который позволяет контролировать выполнение логики представления перед и после ее вызова. -
В этом примере логи печатаются для каждого запроса перед вызовом методов
get()
,post()
и т.д. с использованиемsuper().dispatch()
.
4.2 Добавление функционала через Mixin
В Django часто используется техника Mixin для «встраивания определенной функциональности». Например, можно использовать LoginRequiredMixin (проверка статуса входа), PermissionRequiredMixin (проверка прав) и т.д.
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.http import JsonResponse
class SecuredView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
return JsonResponse({'message': 'Вы аутентифицированы.'})
- Mixin будет рассмотрен более подробно в следующих разделах, посвященных обобщенным представлениям или управлению правами, так что на данном этапе достаточно знать, что функциональность может быть комбинирована таким образом.
5. Простое сравнение с FBV
Категория | FBV (функция основанный представления) | CBV (класс основанный представления) |
---|---|---|
Форма написания | написано в виде функции | написано в виде класса и методов |
Обработка HTTP методов | if request.method == 'GET': ... else: ... |
методы разделены на get() , post() и т.д. |
Вероятность дублирования кода | при усложнении логики легко возникают дублирующие коды | общая логика может быть повторно использована через наследование и Mixin |
Расширяемость | часто общая логика смешивается внутри функции | подходит для решения сложных требований через структуру наследования класса |
Читаемость | хороша для небольших прототипов | лучше поддерживает четкую структуру с увеличением масштаба |
-
FBV удобно писать для малых или простых функций, в то время как CBV хороша для расширяемости и обслуживания.
-
CBV особенно эффективно используется в командных или крупных проектах.
6. Углубленный взгляд: dispatch()
и параметры URL
6.1 Причины для переопределения dispatch()
-
Общая предварительная и постобработка: Вы можете обрабатывать логику, такую как проверка соединения с БД, проверки прав доступа или ведение журнала при каждом запросе.
-
Сопоставление методов: Внутри используется
request.method.lower()
для поиска и вызова методовget()
,post()
,put()
. Если вы хотите дополнительно обработать какой-либо метод, например,PATCH
, вы также можете переопределитьdispatch()
.
class CustomDispatchView(View):
def dispatch(self, request, *args, **kwargs):
print("Логика предварительной обработки здесь.")
response = super().dispatch(request, *args, **kwargs)
print("Логика постобработки здесь.")
return response
6.2 Получение параметров URL
Если в urls.py
задан параметр пути, как <int:user_id>/
, вы можете получить значения с помощью kwargs
в методах get()
, post()
CBV.
# urls.py
urlpatterns = [
path('user/<int:user_id>/', UserDetailView.as_view(), name='user_detail'),
]
# views.py
class UserDetailView(View):
def get(self, request, *args, **kwargs):
user_id = kwargs.get('user_id')
# Запрос в БД по user_id
return HttpResponse(f"User ID: {user_id}")
- Так же, как и в FBV, вы можете извлекать параметры URL из
kwargs
.
7. Более насыщенные примеры из практики: Простой пример доски объявлений
Для тех, кто хочет «использовать класс View немного практичнее!», давайте рассмотрим пример кода, чтобы создать простой список объявлений и страница деталей. (В следующем посте, когда мы рассмотрим обобщенные представления, это будет проще, но здесь мы показываем, что это также возможно с помощью базового класса View.)
# models.py - Пример модели
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
# views.py
from django.views import View
from django.shortcuts import render, get_object_or_404
from .models import Post
# Просмотр списка объявлений
class PostListView(View):
def get(self, request, *args, **kwargs):
posts = Post.objects.order_by('-created_at')
context = {'posts': posts}
return render(request, 'post_list.html', context)
# Просмотр деталей объявления
class PostDetailView(View):
def get(self, request, *args, **kwargs):
post_id = kwargs.get('pk')
post = get_object_or_404(Post, pk=post_id)
context = {'post': post}
return render(request, 'post_detail.html', context)
<!-- post_list.html -->
<!DOCTYPE html>
<html>
<head>
<title>Список объявлений</title>
</head>
<body>
<h1>Список объявлений</h1>
<ul>
{% for post in posts %}
<li>
<a href="{% url 'post_detail' post.id %}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</body>
</html>
<!-- post_detail.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ post.title }}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<p>Дата создания: {{ post.created_at }}</p>
</body>
</html>
# urls.py
from django.urls import path
from .views import PostListView, PostDetailView
urlpatterns = [
path('posts/', PostListView.as_view(), name='post_list'),
path('posts/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]
-
PostListView
: при GET запросе извлекает все объявления и передает их в шаблон (post_list.html
). -
PostDetailView
: находит конкретное объявление по URL параметруpk
и передает его в шаблон (post_detail.html
). -
Таким образом, с помощью базового класса View можно легко сформировать списки и страницы деталей.
Тем не менее, для полной реализации CRUD потребуется логика для создания/обновления/удаления. Более удобную реализацию этого предоставляет обобщенные представления (Generic Views), информация об этом будет подробно изложена в следующей статье!
8. Заключение и анонс следующего поста
Это все о том, как работает базовый класс представления Django и как его можно применять на практике. Основные моменты можно выделить следующим образом:
-
Наследование от django.views.View, переопределение методов
get()
/post()
/dispatch()
для обработки HTTP запросов. -
Запись общей логики в родительском классе и переопределение необходимых частей в дочерних представлениях максимально увеличивает повторное использование кода.
-
Можно легко писать логику представления для различных сценариев, таких как отрисовка шаблонов, JSON ответы, запросы к БД и т.д.
-
Как видно из примера с простым бюллетенем, проект можно создать исключительно с помощью базового класса представления.
Однако для удобной обработки CRUD операций стоит научиться использовать обобщенные представления (Generic Views).
В следующем посте мы соберемся углубленно рассмотреть класс FormView, который упрощает процесс “приема пользовательского ввода, валидации и отображения сообщения об ошибке, если что-то пошло не так”.
Серия CBV продолжается!
- Часть 3: “Упрощение обработки форм с помощью FormView”
- Часть 4: “Использование ListView & DetailView”
- Часть 5: “Реализация CRUD с помощью CreateView, UpdateView, DeleteView”
- … (продолжение следует)
Посмотреть прошлые посты
Дополнительные ресурсы
-
Официальная документация Django: Класс-основанные представления
-
Сообщество Django – здесь можно найти примеры и различные обсуждения.
Надеюсь, что эта статья помогла вам понять структуру и функциональность базового класса представления. В следующем посте мы научимся, как удобно обрабатывать “создание формы → валидация → обработка ошибок → перенаправление при успехе”, используя FormView, так что не пропустите!
“Класс представления Django — это не просто разделение кода по HTTP методам; это мощный инструмент, который может кардинально улучшить расширяемость и поддержку крупных проектов.”
Продолжайте углубляться в CBV и развивайте свою продуктивность в разработке на Django!
댓글이 없습니다.