Django: представления на основе классов (CBV) против представлений на основе функций (FBV)

Это вольный перевод статьи, оригинал которой находится здесь.

Django имеет два типа представлений: представления на основе функций (function-based views, FBV) и представления на основе классов (class-based views, CBV). Первоначально Django начинал только с FBV, но затем добавил CBV как способ шаблонизации функциональности, чтобы вам не приходилось снова и снова писать шаблонный код (то есть один и тот же код).

 

 

 

По своей сути CBV — это классы Python. Django поставляется с различными «шаблонными» CBV с предварительно настроенными функциями, которые вы можете повторно использовать и часто расширять. Затем этим классам присваиваются полезные имена, описывающие, какую функциональность они предоставляют. Вы часто будете видеть, что их называют «универсальными представлениями» (“generic views”), потому что они предоставляют решения для общих требований. У классов есть документация на официальном сайте Django, в которой показано, какие функции предлагаются, какие настройки требуются или возможны, и как их расширять.

Напоминаю, что к представлениям Django предъявляются три требования:

  1. Они доступны для вызова. Представление может быть либо функцией, либо представлением на основе класса. CBV наследуют метод as_view(), который использует метод dispatch() для вызова соответствующего метода в зависимости от HTTP-запроса (get, post и т. д.).
  2. Они должны принимать объект HttpRequest в качестве первого позиционного аргумента.
  3. Они должны возвращать объект HttpResponse или вызывать исключение.

Имейте в виду: CBV не предназначены для замены FBV. Все, чего вы можете достичь с помощью FBV, также достижимо с CBV.

При написании представлений у нас есть выбор: функция или класс? У обоих есть свои плюсы и минусы :~

 

Представления на основе функций

Плюсы

  • Простота реализации
  • Легко читать
  • Явный поток кода (у вас есть полный контроль над тем, что происходит)
  • Легко интегрируется с декораторами
  • Отлично подходит для уникальной логики представления

Минусы

  • Трудно расширять и повторно использовать код
  • Обработка методов HTTP через условное ветвление

Представления-функции проще в реализации, но главный недостаток в том, что в большом проекте Django в представлениях обычно много похожих операций. Например в проекте Django обычно имеются операции CRUD, поэтому этот код повторяется снова и снова без надобности. Представления на основе классов созданы для решения проблем с избыточностью кода.

Пример FBV выглядит примерно так:~

 

Представления на основе классов

Представления-классы – это продвинутый способ создания представлений в Python. В проекте он реализован в виде объектов Python, а не функций. Это не замена FBV, но они обеспечивают преимущества по сравнению с представлениями, основанными на функциях. Уменьшают повторение кода и берут на себя основные операции, такие как удаление и добавление элементов.

Начинающим немного сложнее понять концепцию представлений на основе классов, необходимо тщательно просматривать и изучать документацию.

Плюсы

  • Возможность повторного использования кода. В CBV класс представления может быть унаследован другим классом представления и изменен для различных вариантов использования.
  • DRY — использование CBV помогает уменьшить дублирование кода.
  • Расширяемость кода — CBV можно расширить, чтобы включить больше функций с помощью Mixins.
  • Структурирование кода — в CBV представление на основе классов помогает вам отвечать на разные http-запросы с помощью разных методов экземпляра класса вместо условных операторов ветвления внутри представления на основе функции.
  • Встроенные общие CBV Django.

Минусы

  • Более сложный и трудный в освоении
  • Неявный поток кода (много чего происходит под капотом)
  • Использование декораторов представления требует дополнительного импорта или переопределения метода.

Давайте перепишем наш предыдущий пример FBV как CBV:~

Мы вызываем метод as_view() для обслуживания запроса пользователю. Он в свою очередь вызывает метод dispatch(), чтобы определить, какой метод класса необходимо выполнить, в зависимости от HTTP-запроса. Мы можем реализовать это следующим образом:

Когда вы начнете знакомиться с встроенными общими представлениями Django на основе классов, у вас будет возможность также перезаписать вспомогательные методы, такие как get_form_class и get_template_names, что позволит вам вставить дополнительную логику в эти точки, а не просто переопределить атрибут класса. Одним из примеров является ModelFormMixin — метод form_valid() переопределяется, и связанная модель сохраняется с обновленным значением, хранящимся в self.object().

 

Общие представления Django на основе классов (Generic Class-Based Views)

Generic class-based-views были введены для решения распространенных случаев использования в веб-приложении, таких как создание новых объектов, представления списков, разбиение на страницы, представления архивов и т. д. Они входят в ядро Django, и вы можете реализовать их из модуля django.views.generic.

Они также ускоряют процесс разработки.

Django предоставляет набор представлений и миксинов, общих представлений на основе классов, которые предназначены для решения некоторых наиболее распространенных задач веб-разработки. Цель состоит в том, чтобы вам не приходилось изобретать велосипед снова и снова. Давайте изменим MyCreateView, чтобы он наследовался от django.views.generic.CreateView:

Вау. Куда делся весь код? Ответ, конечно же, заключается в том, что все это находится в django.views.generic.CreateView. Взгляните на Classy Class-Based Views. Это жизненно важный ресурс для понимания общих представлений Django на основе классов. Если вы перейдете к записи для CreateView, вы увидите, что наш маленький двухстрочный класс представления унаследовал более сорока методов и атрибутов класса!

Когда вы наследуетесь от CreateView, вы получаете множество методов и свойств, но вы также получаете что-то вроде договоренности в стиле конфигурации.

  • шаблон должен быть в /<modelname>/<modelname>_form.html по умолчанию — вы можете изменить это, установив атрибут класса template_name и template_name_suffix
  • нам нужно указать атрибуты model и form_class, потому что методы, которые вы унаследовали от CreateView, полагаются на них.
  • нам нужно либо указать success_url в качестве атрибута класса в представлении, либо определить get_absolute_url() в модели, иначе представление не будет знать, куда перенаправляться после успешной отправки формы.
  • нам нужно либо указать атрибут класса fieldsв представлении, либо определить поля в вашей форме. В этом примере я решил сделать последнее. Просто для справки, вот краткий пример того, как это может выглядеть:

 

Стратегии использования Generic Class-Based Views в Django

  • Начните с простого. Каково основное действие рассматриваемого представления? Скажем, например, вам нужен рецепт Recipe, в котором также есть список связанных ингредиентов Ingredient. Начните с DetailView в качестве основы.
  • Добавьте примеси mixins для создания функциональности. Чтобы добавить ингредиенты Ingredient в детальное представление нашего рецепта Recipe, мы используем MultipleObjectMixin, который также предоставляет такие функции, как сортировка и пагинация.
  • Переопределите необходимые методы, чтобы получить функциональность которая необходима. Обратитесь к http://ccbv.co.uk/ или, если ваша IDE (например, PyCharm) позволяет, посмотрите, какие атрибуты и методы класса вам доступны. Структура наследования довольно быстро усложняется, но, к счастью, все методы названы осмысленно, и вам не нужно вникать в во все вызовы или порядок вызовов.

 

 

 

 

Заключение

Среди разработчиков ведутся горячие споры о том, какие представления лучше всего использовать на основе классов или на основе функций. Мы обсудили использование, недостатки и преимущества обоих типов представлений. Все зависит от предпочтений  и потребностей. Как я упоминал в начале этого поста, представления на основе классов не заменяют представления на основе функций. В некоторых случаях хорошо работает представление на основе классов, а в некоторых – лучше использовать представления-функции.

Например, если вы реализуете представление которое выводит список, вы можете просто создать подкласс ListView и переопределить атрибуты.

Если Вы пишете какой-то более сложный функционал, обрабатывая несколько форм одновременно, вам лучше подойдет представление на основе функций.

Опубликовано в Python