Представления-классы (Class-based views, CBV)¶
Представление, в самом общем виде, - это исполняемый(callable) объект, который принимает «на вход» запрос (request), и возвращает ответ(response). В этой роли может выступать не только функция, но и классы - и Django предоставляет нам такие классы и примеры их использования. Такие классы позволяют создавать структурированные, повторно используемые представления, базируясь на возможностях наследования и, в том числе, множественного наследования, - с использованием примесей(mixins). Django включает в себя набор общих(generic) представлений, которые идеально подходят для решения ряда рутинных задач(мы рассмотрим их позже). Ну и конечно, вы можете использовать существующие классы Django для создания собственных, расширяемых и повторно используемых представлений, которые будут полностью удовлетворять вашим потребностям. За более полной информацией обратитесь к документация по классам-представлениям.
Простые примеры¶
Django предлагает нам базовый набор классов представлений, который может использоваться в широком спектре приложений. Все классы-представления наследуют класс View, который обрабатывает «привязку» представления с соответствующими URL, диспетчеризацию HTTP запросов(анализ методов GET, POST и последующий вызов одноименного метода для обработки запроса) и ряд других простых действий. Класс RedirectView служит для простого HTTP перенаправления(redirect), а класс TemplateView расширяет базовый класс, предоставляя возможность обработки шаблонов.
Использование CBV в ваших URLconf¶
Самый простой способ использования общих классов-представлений, - это их создание непосредственно в вашем URLconf. Если вы переопределяете всего несколько простых атрибутов класса, вы можете просто передать эти значения как аргументы метода as_view():
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path("about/", TemplateView.as_view(template_name="about.html")),
]
Любые аргументы, переданные в as_view() переопределят значения этих же аргументов, указанных в теле класса. В данном примере, мы назначаем атрибут template_name для класса TemplateView. Такой же принцип может быть использован для переопределения атрибута url в классе RedirectView.
Использование общих классов-представлений в наследовании¶
Второй, более мощный и гибкий способ использования общих CBV, это использование их в качестве родительских классов. Вы можете указать эти классы в качестве родительских для вашего пользовательского класса-представления и переопределить в теле вашего класса значения атрибутов (таких как template_name) или методы (такие как get_context_data), определив тем самым специфику его работы. Рассмотрим к примеру представление, которое просто отображает один шаблон , about.html. Django предоставляет нам общий класс-представление TemplateView для подобных задач. Все что нам надо сделать, - унаследовать этот класс в дочернем, пользовательском, классе и переопределить имя шаблона:
# some_app/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = "about.html"
Теперь необходимо добавить представление в URLconf. TemplateView является классом, а не функцией, поэтому URL должен указывать на метод as_view(), который работает как обычное представление-функция:
# urls.py
from django.urls import path
from some_app.views import AboutView
urlpatterns = [
path("about/", AboutView.as_view()),
]
Для дополнительной информации по использованию общих(generic) представлений-классов, смотрите раздел общие классы-представления.
Поддержка других методов HTTP¶
Предположим, кто-то хочет получить доступ к списку книг в нашей библиотеке, используя для этого HTTP и наши представления в качестве API. Клиент, работающий с API, будет подключаться к сайту и получать данные о книгах с момента последнего визита. Но если новых книг не появилось, то мы сталкиваемся с проблемой непродуктивного расходования времени CPU, создания ненужных запросов к БД: все это лишь с целью того, чтобы вернуть пользователю ответ, «что новых книг нет». Было бы предпочтительней реализовать в API метод, проверяющий наличие обновлений( дату появления последней новой книги).
В URLconf мы создаем связь URL с представлением, выводящим список книг:
from django.urls import path
from books.views import BookListView
urlpatterns = [
path("books/", BookListView.as_view()),
]
И, собственно, само представление:
from django.http import HttpResponse
from django.views.generic import ListView
from books.models import Book
class BookListView(ListView):
model = Book
def head(self, *args, **kwargs):
last_book = self.get_queryset().latest("publication_date")
response = HttpResponse(
# RFC 1123 date format.
headers={
"Last-Modified": last_book.publication_date.strftime(
"%a, %d %b %Y %H:%M:%S GMT"
)
},
)
return response
Если доступ к представлению осуществляется с помощью запроса GET, в ответе возвращается список объектов (с использованием шаблона book_list.html). Но если клиент отправляет запрос HEAD, ответ имеет пустое тело, а заголовок Last-Modified указывает, когда была опубликована самая последняя книга. На основании этой информации клиент может загрузить или не загрузить полный список объектов.
Асинхронные представления на основе классов¶
Помимо уже показанных обработчиков синхронных методов (def), подклассы View могут определять асинхронные (async def) обработчики методов для использования асинхронного кода с использованием await:
import asyncio
from django.http import HttpResponse
from django.views import View
class AsyncView(View):
async def get(self, request, *args, **kwargs):
# Perform io-blocking view logic using await, sleep for example.
await asyncio.sleep(1)
return HttpResponse("Hello async world!")
В пределах одного класса представления все определяемые пользователем обработчики методов должны быть либо синхронными, используя def, либо асинхронными, используя async def. Исключение ImproperlyConfigured будет вызвано в as_view(), если объявления def и async def смешаны.
Django автоматически обнаружит асинхронные представления и запустит их в асинхронном контексте. Вы можете прочитать больше о поддержке асинхронности в Django и о том, как лучше всего использовать асинхронные представления, в Асинхронная поддержка.