Для новичка, который осваивает Django, представления на основе классов больше похожи на магию чёрного ящика, по крайней мере, у меня при первом знакомстве сложилось именно такое впечатление. Обильные руководства зачастую показывают, какие атрибуты и методы следует определить в вашем классе, чтобы этот ящик работал на вас, но не дают понимания принципа работы. Я хочу залезть под капот фреймворка и строчка за строчкой разобрать, как же работают представления на основе классов. Надеюсь, что по прочтении, Class-based views уже не будут казаться такими пугающими и я подстегну вас к дальнейшему самостоятельному изучению исходников. Возможно, вы думали о фреймворке как о некой магии, которую невозможно понять, но на самом деле это обычный код, написанный опытными разработчиками. Я предполагаю, что у читателя есть базовое представление об ООП в Python и опыт создания проекта на Django. Для более комфортного чтения рекомендую также познакомиться со следующими темами:  *args и **kwargs Замыкания и декораторы @classmethod Множественное наследование и MRO, миксины Функция super() В качестве представления на основе класса я возьму абстрактный AboutView, наследника TemplateView, и на этом примере рассмотрю жизнь класса: классы-предки, формирование функции конструктора, вызов из URLConf, примеси и внутреннюю логику работы. Несмотря на то, что я старался максимально подкрепить мыслительный процесс исходным кодом, я понимаю, что держать в голове нить повествования может быть сложно. Для облегчения задачи я создал блок-схему, на которой можно увидеть все атрибуты и методы класса, откуда они наследуются, и окинуть процесс взаимодействия методов между собой одним взглядом.  Работу с представлениями в Django инициализирует диспетчер URL: он сопоставляет запрошенный URL c шаблонами и, находя совпадения, вызывает указанное представление, которому передаётся экземпляр HttpRequest и аргументы, если они имеются в шаблоне. Давайте посмотрим, как бы выглядел urlpatterns на основе привычного Function-based View (FBV) и на Class-based View (CBV): Сразу бросается в глаза отличие: в FBV мы передаём объект функции about, а не about(), потому что не хотим вызвать её (это будет делать диспетчер). А в CBV — метод класса .as_view(), который вызывается нами. Но этот метод в нашем классе мы не определяли, и в классе непосредственного предка его тоже нет: Откуда же он взялся? Для ответа на этот вопрос следует рассмотреть всю иерархию наследования AboutView. CBV могут наследоваться от множества классов и миксинов, но все CBV берут начало от класса View. Наш класс не исключение: Давайте посмотрим на исходный код View: Для новичка выглядит устрашающе, но мы пойдем по пути, которым следует Django. Поскольку в URLConf вызывается метод as_view(), примем его за отправную точку. Согласно правилам наследования, если метод не найден в текущем классе, поиск будет продолжен далее по списку MRO и в конце концов он будет обнаружен в классе View: В сигнатуре метода есть интересные детали, которые заслуживают отдельного внимания: во‑первых, это декоратор @classonlymethod из django.utils.decorators — потомок builtins.classmethod. Из названия можно догадаться, что декоратор гарантирует вызов только из класса. При вызове метода из экземпляра возбуждается исключение AttributeError. Во‑вторых, привычные **kwargs заменены на **initkwargs — это сделано неспроста. Если бросить взгляд ниже, то можно увидеть, что внутренняя функция view тоже принимает **kwargs параметр. Если бы имя параметра не было изменено, внутренний **kwargs затенил бы внешний, полученный за счёт замыкания. В конечном счёте имя не играет никакой роли, главное здесь оператор распаковки ** — именно он преобразует все именованные параметры в словарь . Что может получить функция в **initkwargs? По задумке создателей Django, в as_view можно сразу передавать необходимые атрибуты и тем самым избежать создания класса. Для примера, наш класс AboutView можно было заменить следующим выражением: В этом случае initkwargs = {'template_name': 'about.html'}. Смотрим код дальше. В цикле for перебираются ключи initkwargs, которые проходят две проверки: Первая позволяет убедиться в том, что ни один из переданных аргументов не использует HTTP‑глагол в качестве имени (они перечислены в атрибуте http_method_names класса View) Дело в том, что методы класса, которые названы в честь HTTP‑глаголов, как раз и будут отвечать за их обработку (т.е. метод get() будет отвечать за запрос c методом GET), мы это ещё увидим позднее. Вторая проверка разрешает нам переопределять только известные атрибуты и методы класса:  То есть Python по списку MRO собирает все методы и атрибуты, определённые в нашем классе, и, если ключ не совпадает ни с одним из них, возбуждает исключение TypeError. Далее по коду мы встречаемся с функцией view(), подробности реализации которой нам сейчас не важны, мы вернёмся к ней позже. На данном этапе достаточно понимания того, что в локальном пространстве имён появляется view с типом function. В следующих двух строках мы добавляем к view два атрибута: .view_class, который содержит ссылку на наш класс AboutView и .view_initkwargs, который содержит словарь initkwargs: и под конец вызываются два wrapper-метода: Те, кто знакомы с декораторами уже заметили, что функция as_view как раз им и является, оборачивая и возвращая функцию view. Врапперы — обычное дело для декораторов, они позволяют заменить метаданные оборачиваемой функции. Если вы посмотрите код враппера, то увидите, что атрибуты __module__, __name__, __qualname__, __doc__, __annotations__ и __dict__ копируются из класса AboutView и метода .dispatch в функцию View. Наконец, мы заканчиванием нашу работу в as_view и на выходе получаем нашпигованный и подготовленный объект функции view, который и возвращаем в URLConf. То есть сейчас URLConf можно было бы представить следующим образом:  , что делает его очень похожим на обычный FBV.  Теперь предположим, что пользователь запросил у нашего сервера web-страницу, диспетчер URL сопоставил паттерн и вызывает нашу функцию view... Если описать коротко, то именно функция view является главным дирижёром: она создаёт экземпляр класса нашего представления, запускает внутреннюю логику и в итоге возвращает response. Взглянем на код: Функция принимает три аргумента. Первым передаётся request в виде экземпляра класса WSGIRequest, далее идут аргументы *args и **kwargs, которые содержат именованные аргументы, захваченные из URL адреса . Вот пример того, что может получить функция: Здесь важно не перепутать **kwargs с**initkwargs, которые доступны функции через замыкание: в **initkwargs мы получаем переопределённые атрибуты для экземпляра класса, а в **kwargs — параметры из URL адреса. Первое что делает функция view — вызывает класс, передавая ему **initkwargs, тем самым создавая его экземпляр. Не стоит смущаться названия переменной self, обычно мы привыкли видеть её в параметрах методов. Здесь это просто переменная, что появляется в локальной области видимости, и которой мы присваиваем ссылку на экземпляр класса. Создавая экземпляр, мы неявно вызываем инициализатор класса __init__, который, проходя по словарю **kwargs (но мы-то помним, что на самом деле он **initkwargs :), создаёт атрибуты экземпляра. Теперь у нас в переменной self сохранён экземпляр класса AboutView. После вызывается метод setup, который принимает аргументы, переданные view (те, что захватили из URL), и сохраняет их в экземпляре класса, что делает их доступными для всех других методов экземпляра: Помимо этого он проверяет, определены ли у экземпляра обработчики методов GET и HEAD: если self.get определён, а self.head нет, то метод создаёт атрибут self.head и перенаправляет на self.get. После вызова setup() в функции view() выполняется еще одна проверка, чтобы убедиться, что у self есть атрибут запроса: Сообщение об ошибке даёт нам объяснение, зачем эта проверка нужна: метод setup() может быть переопределён, создавая вероятность того, что атрибут request может быть забыт. По итогу функция возвращает нам результат выполнения следующего метода - dispatch(). Работа метода dispatch() отражает его название:  Вначале мы берём HTTP-метод из запроса (request.method), приводим его к нижнему регистру и проверяем, а метод ли он, сравнивая с уже знакомым списком разрешённых методов из http_method_names. Если метод не найден в атрибуте http_method_names (условие else) или в экземпляре и его родителях (третий аргумент функции getattr), вызывается http_method_not_allowed , определённый в классе View: http_method_not_allowed возвращает HttpResponseNotAllowed со списком методов, которые мы определили для нашего класса. Если же такой глагол нашёлся, диспетчер назначает соответствующий метод переменной handler (для OPTIONS → options,для GET → get, для POST → post). В конце работы dispatch() возвращает нам результат выполнения handler(), что, исходя из вышесказанного, вернёт нам либо HttpResponse с кодом 405, либо результат нашего определённого метода. Если мы вернёмся и посмотрим полный код класса View, то увидим, что  в нём предопределён только один метод options(). Он вернёт нам ответ на запрос с заголовком Allow с поддерживаемыми методами. Но что делать, если нам нужно обработать запрос GET? На этом моменте полномочия базового класса View всё :) и в игру вступает его наследник TemplateView, в котором нужный метод определён: Получая знакомые уже нам атрибуты, класс формирует контекст для шаблона, вызывая метод get_context_data из примеси ContextMixin.  Миксин не занимается rocket science, а всего лишь берёт словарь ключевых аргументов, полученных из URL адреса, добавляет туда ключ 'view', который ссылается на наш экземпляр класса (таким образом вы сможете обратиться к экземпляру класса прямо из шаблона), и под конец примешивает словарь extra_context, если вы вдруг его переопределяли. Получив контекст, TemplateView может его отрендерить при помощи примеси TemplateResponseMixin и её метода render_to_response. Имена атрибутов информативны сами по себе (но если что вы всегда можете заглянуть в документацию). Если вдруг вы забыли, то, наследуясь от класса TemplateView, мы переопределили имя шаблона на 'about.html', именно этот шаблон и будет использоваться для рендера. Точно так же вы можете переопределять остальные параметры нашего класса, чтобы получить необходимое поведение CBV. Конечно, собирать все атрибуты при множественном наследовании выматывающая работа, но здесь нам на помощь приходит сайт Classy Class-Based Views, в котором вы сразу видите все атрибуты и методы класса и его родителей. Теперь не требуется бежать на StackOverflow, чтобы нагуглить ответ, можно использовать перегрузку аттрибутов с пониманием. В этом миксине берётся дефолтный TemplateResponse (если вы его не переопределяли), ему передаётся контекст и список шаблонов, полученный с помощью несложного метода get_template_names : который возвращает имя шаблона внутри списка или возбуждает ошибку, если оно не определено. И, как финальный результат, экземпляр TemplateResponse возвращается в метод get(), который далее передаёт по цепочке в dispatch() и view(), и на этом работа представления завершается. Конечно, разобрав один из наиболее простых CBV сложно сказать, что уверенно ими владеете, впереди вас ждут более интересные Generic display views, такие как DetailView и ListView с более сложными миксинами и разветвлённым наследованием, но хочется верить, что, прочитав этот материал, вы сможете разобраться в них самостоятельно. А пока давайте подведём итог полученным знаниям: CBV базируется на множестве классов и миксинов, но во главе стоит класс View с конструктором экземпляра и методом as_view(). Вызов метода as_view() в URLConf возвращает нам функцию view(), которую Django будет вызывать при совпадении адреса с паттерном Вызов функции view() создаёт экземпляр представления и запускает цепочку обработки запроса Метод dispach() определяет HTTP-глагол и направляет к соответствующему методу, если его нет, возвращает HttpResponse с кодом 405 В конце цепочки методов-обработчиков нам возвращается экземпляр TemplateResponse, как результат выполнения представления Classy Class-Based Views — ресурс, позволяющий для каждого CBV увидеть все наследуемые атрибуты и методы Epydoc.pythondiary.com — аналогичный ресурс, предоставляющий информацию в несколько ином формате. Отлично дополняет Classy Class Документация Django. Базовые представления на основе классов P.S.: На написание этой статьи меня вдохновил пост в блоге Django Deconstructed.