Что такое миксины django
Что такое миксины в Python и как их использовать.
В Python нет какого либо специального синтаксиса для поддержки миксинов, по этому классы миксинов, легко можно перепутать с обычными классами, но при этом у них действительно очень большая как семантическая, так и реальная разница с обычными классами.
Так как для реализации поведения миксинов используется простое множественное наследование, то это требует от программиста большой дисциплины, поскольку нарушает одно из основных допущений для миксинов: их ортогональность к дереву наследования, т. е. классы, не зависят друг от друга. В Python миксины живут в обычном дереве наследования, предоставляя дополнительную функциональность и избегают создания иерархий, которые слишком сложны для понимания программистом.
Пример множественного наследования.
Пример использования класса миксина/примеси.
В отличие от приведенного выше примера, класс миксина не предназначен для использования отдельно. Он предоставляет новые методы или переопределяет имеющиеся методы.
Например, в стандартной библиотеке Python, в модуле socketserver есть несколько миксинов. Выдержка из документации:
С помощью этих классов миксинов могут быть созданы поточные версии каждого типа сервера. Например, ThreadingUDPServer создается следующим образом:
Простой пример для понимания поведения классов миксинов.
Иногда молодые программисты не до конца понимают принцип MRO в Python и по этому в некоторых случаях не правильно используют классы миксинов.
Классы-примеси (mixin) в Python
Введение
Примеры
Mixin
Таким образом, чтобы дать классы для Car и Часовой возможность использовать радио, вы можете переопределить Car из предыдущего примера и написать это:
С миксинами важно то, что они позволяют вам добавлять функциональные возможности к разным объектам, которые не разделяют «основной» подкласс с этой функциональностью, но, тем не менее, совместно используют код для него. Без миксинов сделать что-то похожее на приведенный выше пример будет гораздо сложнее и / или может потребоваться некоторое повторение.
Переопределение методов в миксинах
Например, возьмите следующие классы
В этом случае класс Mixin2 является базовым классом, расширенным с помощью Mixin1 и, наконец, с помощью BaseClass. Таким образом, если мы выполним следующий фрагмент кода:
Мы видим возвращаемый результат из базового класса. Это может привести к непредвиденным ошибкам в логике вашего кода и должно учитываться и учитываться
Синтаксис
Параметры
Примечания
Научим основам Python и Data Science на практике
Это не обычный теоритический курс, а онлайн-тренажер, с практикой на примерах рабочих задач, в котором вы можете учиться в любое удобное время 24/7. Вы получите реальный опыт, разрабатывая качественный код и анализируя реальные данные.
Documentation
Using mixins with class-based views¶
This is an advanced topic. A working knowledge of Django’s class-based views is advised before exploring these techniques.
Context and template responses¶
Two central mixins are provided that help in providing a consistent interface to working with templates in class-based views.
ContextMixin Every built in view which needs context data, such as for rendering a template (including TemplateResponseMixin above), should call get_context_data() passing any data they want to ensure is in there as keyword arguments. get_context_data() returns a dictionary; in ContextMixin it returns its keyword arguments, but it is common to override this to add more members to the dictionary. You can also use the extra_context attribute.
Building up Django’s generic class-based views¶
DetailView : working with a single Django object¶
To show the detail of an object, we basically need to do two things: we need to look up the object and then we need to make a TemplateResponse with a suitable template, and that object as context.
ListView : working with many Django objects¶
MultipleObjectMixin also overrides get_context_data() to include appropriate context variables for pagination (providing dummies if pagination is disabled). It relies on object_list being passed in as a keyword argument, which ListView arranges for it.
Using Django’s class-based view mixins¶
Now we’ve seen how Django’s generic class-based views use the provided mixins, let’s look at other ways we can combine them. We’re still going to be combining them with either built-in class-based views, or other generic class-based views, but there are a range of rarer problems you can solve than are provided for by Django out of the box.
Not all mixins can be used together, and not all generic class based views can be used with all other mixins. Here we present a few examples that do work; if you want to bring together other functionality then you’ll have to consider interactions between attributes and methods that overlap between the different classes you’re using, and how method resolution order will affect which versions of the methods will be called in what order.
The reference documentation for Django’s class-based views and class-based view mixins will help you in understanding which attributes and methods are likely to cause conflict between different classes and mixins.
Using SingleObjectMixin with View¶
We can hook this into our URLs easily enough:
Using SingleObjectMixin with ListView ¶
ListView provides built-in pagination, but you might want to paginate a list of objects that are all linked (by a foreign key) to another object. In our publishing example, you might want to paginate through all the books by a particular publisher.
Now we can write a new PublisherDetailView :
The paginate_by is deliberately small in the example so you don’t have to create lots of books to see the pagination working! Here’s the template you’d want to use:
Avoid anything more complex¶
Using FormMixin with DetailView ¶
Think back to our earlier example of using View and SingleObjectMixin together. We were recording a user’s interest in a particular author; say now that we want to let them leave a message saying why they like them. Again, let’s assume we’re not going to store this in a relational database but instead in something more esoteric that we won’t worry about here.
At this point it’s natural to reach for a Form to encapsulate the information sent from the user’s browser to Django. Say also that we’re heavily invested in REST, so we want to use the same URL for displaying the author as for capturing the message from the user. Let’s rewrite our AuthorDetailView to do that.
Our new AuthorDetailView looks like this:
A better solution¶
The number of subtle interactions between FormMixin and DetailView is already testing our ability to manage things. It’s unlikely you’d want to write this kind of class yourself.
In this case, you could write the post() method yourself, keeping DetailView as the only generic functionality, although writing Form handling code involves a lot of duplication.
Alternatively, it would still be less work than the above approach to have a separate view for processing the form, which could use FormView distinct from DetailView without concerns.
An alternative better solution¶
The AuthorDetailView view is almost the same as when we first introduced AuthorDetailView ; we have to write our own get_context_data() to make the AuthorInterestForm available to the template. We’ll skip the get_object() override from before for clarity:
Finally we bring this together in a new AuthorView view. We already know that calling as_view() on a class-based view gives us something that behaves exactly like a function based view, so we can do that at the point we choose between the two subviews.
You can pass through keyword arguments to as_view() in the same way you would in your URLconf, such as if you wanted the AuthorInterestFormView behavior to also appear at another URL but using a different template:
More than just HTML¶
Where class-based views shine is when you want to do the same thing many times. Suppose you’re writing an API, and every view should return JSON instead of rendered HTML.
We can create a mixin class to use in all of our views, handling the conversion to JSON once.
For example, a JSON mixin might look something like this:
Check out the Serializing Django objects documentation for more information on how to correctly transform Django models and querysets into JSON.
Equally we could use our mixin with one of the generic views. We can make our own version of DetailView by mixing JSONResponseMixin with the BaseDetailView – (the DetailView before template rendering behavior has been mixed in):
Как работают Django Class-based views
Для новичка, который осваивает Django, представления на основе классов больше похожи на магию чёрного ящика, по крайней мере, у меня при первом знакомстве сложилось именно такое впечатление. Обильные руководства зачастую показывают, какие атрибуты и методы следует определить в вашем классе, чтобы этот ящик работал на вас, но не дают понимания принципа работы.
Я хочу залезть под капот фреймворка и строчка за строчкой разобрать, как же работают представления на основе классов. Надеюсь, что по прочтении, Class-based views уже не будут казаться такими пугающими и я подстегну вас к дальнейшему самостоятельному изучению исходников. Возможно, вы думали о фреймворке как о некой магии, которую невозможно понять, но на самом деле это обычный код, написанный опытными разработчиками.
Background
Я предполагаю, что у читателя есть базовое представление об ООП в Python и опыт создания проекта на Django. Для более комфортного чтения рекомендую также познакомиться со следующими темами:
Несмотря на то, что я старался максимально подкрепить мыслительный процесс исходным кодом, я понимаю, что держать в голове нить повествования может быть сложно. Для облегчения задачи я создал блок-схему, на которой можно увидеть все атрибуты и методы класса, откуда они наследуются, и окинуть процесс взаимодействия методов между собой одним взглядом.
0. URL dispatcher
Работу с представлениями в Django инициализирует диспетчер URL: он сопоставляет запрошенный URL c шаблонами и, находя совпадения, вызывает указанное представление, которому передаётся экземпляр HttpRequest и аргументы, если они имеются в шаблоне.
Давайте посмотрим, как бы выглядел urlpatterns на основе привычного Function-based View (FBV) и на Class-based View (CBV):
Исходный код класса TemplateView
1. Class View
Иерархия наследования класса AboutView
Давайте посмотрим на исходный код View:
Исходный код класса View
Для новичка выглядит устрашающе, но мы пойдем по пути, которым следует Django.
Первая позволяет убедиться в том, что ни один из переданных аргументов не использует HTTP‑глагол в качестве имени (они перечислены в атрибуте http_method_names класса View )
Дело в том, что методы класса, которые названы в честь HTTP‑глаголов, как раз и будут отвечать за их обработку (т.е. метод get() будет отвечать за запрос c методом GET), мы это ещё увидим позднее.
Вторая проверка разрешает нам переопределять только известные атрибуты и методы класса:
и под конец вызываются два wrapper-метода:
, что делает его очень похожим на обычный FBV.
2. View function
Если описать коротко, то именно функция view является главным дирижёром: она создаёт экземпляр класса нашего представления, запускает внутреннюю логику и в итоге возвращает response. Взглянем на код:
который, проходя по словарю **kwargs (но мы-то помним, что на самом деле он **initkwargs :), создаёт атрибуты экземпляра.
После вызова setup() в функции view() выполняется еще одна проверка, чтобы убедиться, что у self есть атрибут запроса:
Сообщение об ошибке даёт нам объяснение, зачем эта проверка нужна: метод setup() может быть переопределён, создавая вероятность того, что атрибут request может быть забыт.
3. dispatch()
Работа метода dispatch() отражает его название:
http_method_not_allowed возвращает HttpResponseNotAllowed со списком методов, которые мы определили для нашего класса.
Он вернёт нам ответ на запрос с заголовком Allow с поддерживаемыми методами.
Но что делать, если нам нужно обработать запрос GET?
4. get()
5. TemplateResponseMixin
Имена атрибутов информативны сами по себе (но если что вы всегда можете заглянуть в документацию).
Точно так же вы можете переопределять остальные параметры нашего класса, чтобы получить необходимое поведение CBV. Конечно, собирать все атрибуты при множественном наследовании выматывающая работа, но здесь нам на помощь приходит сайт Classy Class-Based Views, в котором вы сразу видите все атрибуты и методы класса и его родителей. Теперь не требуется бежать на StackOverflow, чтобы нагуглить ответ, можно использовать перегрузку аттрибутов с пониманием.
В этом миксине берётся дефолтный TemplateResponse (если вы его не переопределяли), ему передаётся контекст и список шаблонов, полученный с помощью несложного метода get_template_names :
который возвращает имя шаблона внутри списка или возбуждает ошибку, если оно не определено.
Заключение
Конечно, разобрав один из наиболее простых CBV сложно сказать, что уверенно ими владеете, впереди вас ждут более интересные Generic display views, такие как DetailView и ListView с более сложными миксинами и разветвлённым наследованием, но хочется верить, что, прочитав этот материал, вы сможете разобраться в них самостоятельно.
А пока давайте подведём итог полученным знаниям:
Вызов функции view() создаёт экземпляр представления и запускает цепочку обработки запроса
Метод dispach() определяет HTTP-глагол и направляет к соответствующему методу, если его нет, возвращает HttpResponse с кодом 405
Полезные ссылки
Classy Class-Based Views — ресурс, позволяющий для каждого CBV увидеть все наследуемые атрибуты и методы
Использование миксинов с представлениями на основе классов¶
Контекст и шаблонные ответы¶
Предоставляются два центральных миксина, которые помогают обеспечить согласованный интерфейс для работы с шаблонами в представлениях, основанных на классах.
Построение общих представлений Django на основе классов¶
DetailView : работа с одним объектом Django¶
Чтобы показать детали объекта, нам в основном нужно сделать две вещи: найти объект, а затем сделать TemplateResponse с подходящим шаблоном и этим объектом в качестве контекста.
ListView : работа с большим количеством объектов Django¶
Использование миксинов представления Django на основе классов¶
Теперь мы увидели, как общие представления Django, основанные на классах, используют предоставленные миксины, давайте рассмотрим другие способы их комбинирования. Мы по-прежнему будем комбинировать их либо со встроенными представлениями на основе классов, либо с другими общими представлениями на основе классов, но есть ряд более редких проблем, которые вы можете решить, чем те, которые предусмотрены Django из коробки.
Не все миксины можно использовать вместе, и не все представления, основанные на общих классах, можно использовать со всеми другими миксинами. Здесь мы приводим несколько примеров, которые работают; если вы хотите объединить другие функциональные возможности, то вам придется рассмотреть взаимодействие между атрибутами и методами, которые пересекаются между различными классами, которые вы используете, и как method resolution order будет влиять на то, какие версии методов будут вызываться в каком порядке.
Справочная документация для Django class-based views и class-based view mixins поможет вам понять, какие атрибуты и методы могут вызвать конфликт между различными классами и миксинами.
Использование SingleObjectMixin с View¶
Мы можем легко подключить это к нашим URL-адресам:
Использование SingleObjectMixin с ListView ¶
ListView обеспечивает встроенную пагинацию, но вы можете захотеть просмотреть список объектов, которые все связаны (внешним ключом) с другим объектом. В нашем примере с издательством вы можете захотеть постранично просмотреть все книги определенного издательства.
Теперь мы можем написать новый PublisherDetailView :
В примере paginate_by намеренно сделан маленьким, чтобы вам не пришлось создавать много книг, чтобы увидеть, что пагинация работает! Вот шаблон, который вы хотите использовать:
Избегайте чего-то более сложного¶
Использование FormMixin с DetailView ¶
Вспомните наш предыдущий пример использования View и SingleObjectMixin вместе. Мы регистрировали интерес пользователя к определенному автору; теперь скажем, что мы хотим позволить ему оставить сообщение о том, почему он ему нравится. Опять же, давайте предположим, что мы не собираемся хранить это в реляционной базе данных, а вместо этого в чем-то более эзотерическом, о чем мы не будем здесь беспокоиться.
Наш новый AuthorDetailView выглядит следующим образом:
Лучшее решение¶
Количество тонких взаимодействий между FormMixin и DetailView уже проверяет нашу способность управлять вещами. Маловероятно, что вы захотите написать такой класс самостоятельно.
В этом случае вы могли бы написать метод post() самостоятельно, сохранив DetailView как единственную общую функциональность, хотя написание кода обработки Form подразумевает много дублирования.
В качестве альтернативы, это было бы менее трудоемко, чем вышеописанный подход, иметь отдельное представление для обработки формы, которое могло бы использовать FormView в отличие от DetailView без проблем.
Альтернативное лучшее решение¶
Вы можете передавать аргументы ключевых слов в as_view() таким же образом, как и в URLconf, например, если вы хотите, чтобы поведение AuthorInterestFormView также появлялось в другом URL, но с использованием другого шаблона:
Больше, чем просто HTML¶
Представления, основанные на классах, эффективны, когда вы хотите делать одно и то же много раз. Предположим, вы пишете API, и каждое представление должно возвращать JSON вместо HTML.
Мы можем создать класс mixin, который будет использоваться во всех наших представлениях, обрабатывая преобразование в JSON один раз.
Например, миксин JSON может выглядеть следующим образом:
Ознакомьтесь с документацией Сериализация объектов Django для получения дополнительной информации о том, как правильно преобразовывать модели Django и наборы запросов в JSON.