Рубрики
Без рубрики

Копание просмотров на основе класса Django – 1

Этот пост был первоначально опубликован на цифровой кошке Django 3 был выпущен в конце 2019 года, поэтому I… Tagged с Django, OOP, Python.

Копание просмотров на основе классов Django (серия 3 частей)

Этот пост был первоначально опубликован в Цифровой кот

Django 3 был выпущен в конце 2019 года, поэтому я думаю, что пришло время вернуться к своей успешной серии постов о классных взглядах в Джанго. Эти сообщения датируются 2013 году и были написаны с учетом Django 1.5, и с примерами из этой базы кода. Теперь Django уже на две версии старше, но классовые взгляды по-прежнему являются важной частью структуры, поэтому я считаю, что имеет смысл обновить содержание этих постов. Более того, у меня еще не было возможности изучать Django 3, поэтому, согласно традиции этого блога, я сделаю свое личное исследование доступным для всех.

Если вы начинающий программист Python и только что обратились к Django, чтобы начать свою карьеру в области веб-разработки, скорее всего, вы были озадачены многими вещами, а классовые взгляды (CBV) определенно среди них. CBV, по -видимому, очень просты в использовании, в простых случаях, но может быть неясно, как расширить их, чтобы соответствовать более сложным случаям использования, поскольку развитие проекта продолжается. Официальная документация очень хороша, но для освоения CBV вам необходимо понимать объектно-ориентированные концепции, такие как классы (ну, очевидно), делегирование и переопределение метода.

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

Взгляды на основе классов, просмотры Django, основанные на классах Python. Это означает, что, чтобы овладеть ими, вам нужно понимать как взгляды Джанго, так и классы Python, поэтому давайте быстро определяем их.

Представление Django – это часть кода, который обрабатывает входящий HTTP -запрос и возвращает HTTP -ответ, не более того, не меньше. Класс Python-это реализация объектно-ориентированной концепции класса на языке питона.

Итак, представление должно быть Callible , и это включает в себя функции и классы. Таким образом, чтобы понять преимущества классовых представлений по сравнению с видами функций, мы обсудим достоинства классов по сравнению с функциями. Последнее предложение может быть названием «10 -таковой книги по программированию» (за которым следует еще одна книга тома под названием «Достоинства функций над классами»), поэтому я просто собираюсь поцарапать поверхность вопроса здесь. Если вы хотите больше выпадать в тему, пожалуйста, прочитайте серию на Python 3 OOP, который я связал выше, где вы найдете все детали кровага, к которым вы жаждете.

Основные классы – это реализация инкапсуляции: они представляют собой способ соединения данных и функций. Делая это, класс теряет динамическую сущность процедуры, которая существует только во время его работы, и становится живой сущностью, то, что там сидит, ухаживает за своими данными и реагирует, когда мы называем его функции (методы).

Хорошей аналогией для класса является машина конечного состояния: как только класс был инициализирован, методы-это то, что мы используем, чтобы машина перемещалась между состояниями. Если мы не вызовываем методы, класс просто ждет там, не жалуясь.

В качестве примера, давайте посмотрим на очень простую процедуру, которая извлекает четные числа из итерационного, подобного списку

def extract_even_numbers(alist):
    return [i for i in alist if i%2 == 0]

Пример очень тривиальный, но, поскольку код естественно, имеет тенденцию становиться все более сложным, лучше начать с простых примеров. Классная версия этой функции может быть написана как

class EvenExtractor:
    def __init__(self, alist):
        self.l = alist

    def extract(self):
        return [i for i in self.l if i%2 == 0]

Они очень похожи, и может показаться, что мы ничего не изменили. Действительно, разница тонкая, но замечательная. Теперь Evelextractor Класс имеет две части, первой из которых является инициализация, а вторая – фактическая извлечение, и мы можем получить класс в одном из трех состояний: до инициализации ( eneextractor ), после инициализации ( E ([1, 4,5,7,12]) ) и после экстракции ( l.extract () ).

Таким образом, преобразование процедуры в класс, мы получили богатый инструмент, который может выполнять его задание шаг за шагом и, в целом, может работать не линейным образом, как мы могли бы добавить дополнительные методы и, следовательно, больше состояний.

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

(Вы можете заметить, что я не упоминаю наследство, а делегирование, которое осуществляется как композицией, так и наследством. Я сильный сторонник принципа дизайна OO, который утверждает, что «благоприятный состав над наследством». Я продолжаю читать слишком много знакомств, чтобы объектно-ориентированные, которые слишком сильно напрягают механизм наследования и оставляют композицию в стороне, поднимая поколение программистов ООП, которые вместо строительства систем, населенных многими небольшими совместными объектами, создают кошмары, зараженные гигантскими универсальными вещами это иногда напоминает больше операционной системы, чем системной компонент.)

Давайте продолжим приведенный выше пример, улучшая __init__ Метод Evelextractor учебный класс:

class EvenExtractor:
    def __init__(self, alist):
        self.l = [int(elem) for elem in alist]

    def extract(self):
        return [i for i in self.l if i%2 == 0]

Теперь класс выполняет важное действие на этапе своей инициализации, преобразуя все элементы ввода в целые числа. Однако через несколько дней после этого изменения мы могли бы понять, что мы также можем с выгодным использованием класса, который извлекает нечетные элементы из списка. Быть ответственными объектно -ориентированными программистами мы пишем

class OddExtractor(EvenExtractor):
    def extract(self):
        return [i for i in self.l if i%2 != 0]

И назовите это днем. Через механизм наследования, выраженный этим (Evelextractor) Подпись нового класса, мы сначала определили то, что точно так же, как Evelextractor , с теми же методами и атрибутами, но с другим именем. Затем мы изменили поведение нового класса, но только для части извлечения, переопределив метод.

Подводя итог урок: Использование классов и делегирования вы можете создать машины с конечным состоянием, которые легко настраиваются в соответствии с вашими точными потребностями. Это, очевидно, является лишь одной из многих точек зрения, с которой вы можете рассмотреть классы, но это то, что нам нужно понять Django CBV.

Давайте начнем обсуждать практическое использование того, что мы узнали до сих пор, рассмотрив, как Django использует классы Python и делегирование для предоставления взглядов.

Вид Django является прекрасным примером конечной машины. Он требует входящего запроса и заставляет его проходить через разные шаги обработки до получения окончательного ответа, который затем отправляется обратно пользователю. CBV-это способ для программиста написать свои взгляды, использующие объектно-ориентированную парадигму. В этом контексте общие представления на основе класса являются «батареи, включенные» видов Django, строительные блоки, которые структура предоставляет из коробки.

Давайте углубимся в один из примеров официальных документов Джанго; Здесь Вы находите API любимого Посмотреть список , общий вид, чтобы справиться со списком вещей (извлеченные из базы данных). Я слегка упростил пример, приведенный документацией, чтобы избежать слишком большого количества на нашей тарелке.

from django.views.generic.list import ListView

from articles.models import Article

class ArticleListView(ListView):

    model = Article

Этот пример предполагает, что Статьи Ваше приложение и Статья является одной из его моделей.

Вы можете увидеть здесь полную силу наследования. Мы только что вывели ArticleListView от ListView и изменил модель Атрибут класса. Как это может работать? Как этот класс может процесс входящих запросов и каковы выходы? Официальная документация гласит «пока эта точка зрения выполняется, Object_list будет содержать список объектов (обычно, но не обязательно вопрос, на который работает представление. «; Однако это оставляет много темных углов, и если вы новичок, скорее всего, вы уже потеряны.

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

CBV не может быть напрямую использоваться в вашем диспетчере URL; Вместо этого вы должны дать результат as_view Метод ( code ), который определяет функцию, которая экземплярует класс ( code ) и вызывает отправка Метод ( код ); Затем возвращается функция ( код ) для использования в диспетчере URL. Как пользователь, нас интересует только тот факт, что точка входа класса (метод, вызванный, когда запрос попадает в URL -адрес, связанный с ним), является отправка Анкет

Давайте использовать эти знания, чтобы распечатать строку на консоли каждый раз, когда запрос обслуживается нашим CBV. Я буду проходить через эту простую задачу шаг за шагом, так как она показывает, как именно вам приходится иметь дело с CBV при решении реальных проблем.

Если мы определим ArticleListView класс таким образом

from django.views.generic.list import ListView

from articles.models import Article

class ArticleListView(ListView):

    model = Article

    def dispatch(self, request, *args, **kwargs):
        return super().dispatch(request, *args, **kwargs)

Класс не меняет своего поведения. То, что мы сделали, было переопределить отправка Метод с вызовом к методу родителя, то есть мы явно писали, что делает Python по умолчанию. Вы можете найти подробную информацию о супер в Официальная документация и в этот пост в блоге. Пожалуйста, убедитесь, что вы понимаете нотацию Star и Double Star, чтобы определить переменное количество аргументов; Официальная документация Здесь Анкет

Поскольку представления автоматически называются структурой, последние ожидают, что они будут соблюдать очень специфический API, поэтому при переоценке метода вы должны предоставить ту же подпись исходной. Подпись отправка можно найти Здесь Анкет

отправка Метод получает Запрос Аргумент, какой тип Httprequest ( документация ), поэтому мы можем распечатать ее на консоли со стандартным Печать функция

from django.views.generic.list import ListView

from articles.models import Article

class ArticleListView(ListView):

    model = Article

    def dispatch(self, request, *args, **kwargs):
        print(request)
        return super().dispatch(request, *args, **kwargs)

Это печатает содержание Запрос Объект на стандартном выводе сервера, который запускает проект Django. Если вы запускаете сервер разработки Django, вы найдете вывод на текстовой консоли, где вы выпустили команду Python Manage.py Рансервер .

Это, в словах, является стандартным способом работы с Django CBGV: наследуя от предопределенного класса, определить, какие методы вам нужно изменить, переопределить их, соответствующие их подписи и вызывая код родителя где -то в новом коде.

Полный список методов ListView Использование при обработке входящих запросов указано на его Официальная страница документации в разделе «Метод блок -схемы»; В разделе «Предки (MRO)» вы можете увидеть, что ListView наследует от большого количества других классов. MRO означает заказ на разрешение метода и должен иметь дело с множественным наследством: если вы хотите справиться с одной из самых сложных тем Python, не стесняйтесь читать это Анкет

Вернуться к нашему ArticleListView Анкет отправка Метод родителя читает метод Атрибут Запрос объект и выбирает обработчик для обработки самого запроса ( код ): это означает, что если request.method это 'Get' , который является HTTP, чтобы сказать, что мы Чтение Ресурс, отправка Позвонит получить Метод класса.

получить Метод Посмотреть список происходит от его BaselistView Предок ( Документы , CODE ). Как видите, функция в основном инициализирует атрибут Object_list с результатом вызова get_queryset () , создает контекст, вызывающий метод get_context_data и вызывает render_to_response Анкет

Ты все еще со мной? Не сдавайтесь, мы почти закончили, по крайней мере, с ListView. Метод get_queryset происходит из Несколькообъективмиксин предок ListView ( документы , code ) и просто получает все объекты данной модели ( code ) Запуск queryset.model._default_manager.all () Анкет Значение модель это то, что мы настроили в нашем классе, когда писали модель . Я надеюсь, что в этот момент что -то начнет иметь смысл в вашей голове.

Это все, на самом деле. Наш ArticleListView класс извлекает все Статья Объекты из базы данных и вызывает шаблон, передающий контекст, который содержит одну переменную, Object_list , Instansed со списком извлеченных объектов.

Ты удовлетворен? На самом деле мне все еще интересно в шаблоне и контексте. Давайте посмотрим, что мы можем найти по этим темам. Прежде всего, когда класс вызывает render_to_response Он использует код, который исходит из его TemplaterSponsemixin предок ( документы , code ); Метод инициализирует класс TemplaterSponse прохождение шаблона и контекст. Шаблон, посредством ряда звонков, за которыми вы можете следовать самостоятельно, исходит от Template_Name ( код ); В то время как TemplaterSponsemixin Инициализирует его как Нет ( код ), ListView Выполняет некоторые магические трюки через предков ( code ), чтобы вернуть шаблон, который имя вытекает из данной модели. Короче говоря, наш ArticleListView , определение Статья Модель, автоматически использует шаблон, который называется article_list.html Анкет

Можем ли мы изменить это поведение? Конечно! В конце концов, это точка использования классов вместо функций: легко настраиваемое поведение. Мы можем изменить определение нашего класса на

from django.views.generic.list import ListView

from articles.models import Article

class ArticleListView(ListView):

    model = Article
    template_name = 'sometemplate.html'

Давайте рассмотрим, что это делает шаг за шагом. Когда ответ создается, Django запускает код render_to_response ( код ), который в свою очередь вызывает get_template_names . Обратите внимание на то, что этот метод возвращает список имен, поскольку Django будет использовать первый доступный среди них, сканируя их по порядку. Этот метод переопределен в Посмотреть список по его суперклассу Несколькообъективноплектрический ответ -эмиксин ( код ). Это называет тот же метод своего собственного Superclass TemplaterSponsemixin ( code ), который возвращает атрибут, который мы устанавливаем в ArticleListView класс ( код ). Смешивание продолжается и добавляет к списку имя файла шаблона, полученное из модели ( code ) и, наконец, возвращает список, который на данный момент является ['Singemplate.html', 'article_list.html'] Анкет

Что касается контекста, помните, что это только словарь значений, которые вы хотите иметь в состоянии получить доступ при составлении шаблона. Имена переменных внутри контекста, формата данных и содержания данных полностью зависит от вас. Однако при использовании CBGV вы обнаружите в своем контексте некоторые переменные, которые были созданы предками вашей точки зрения, как это происходит для object_list . Что если вы хотите показать страницу со списком всех статей, но вы хотите добавить значение в контекст?

Простая задача: вам просто нужно переопределить функцию, которая создает контекст и изменяет его поведение. Скажите, например, что мы хотим показать количество общих читателей нашего сайта, а также список статей. Предполагая, что А Читатель Модель доступна, мы можем написать

from django.views.generic.list import ListView

from articles.models import Article, Reader

class ArticleListView(ListView):
    model = Article

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['readers'] = Reader.objects.count()
        return context

Как всегда, при переопределении метода мы должны спросить себя, нужно ли нам вызвать исходный метод. В этом случае мы хотим просто увеличить содержание контекста и не заменить его, поэтому мы называем super (). get_context_data (** kwargs) Во -первых, и мы добавляем значение, которое нам нужно для этого. Обратите внимание на то, что это может быть не всегда так, так как это зависит от логики вашего переопределения.

В этом первом посте я попытался раскрыть некоторые загадки, стоящие за CBV и CBGV в Джанго, показывая, что именно происходит с запросом GET, который попадает в классную точку зрения. Надеемся, что этот вопрос теперь немного демистифицирован! В следующих постах я буду обсуждать DetailView , общий вид, чтобы показать подробную информацию об объекте, как создавать пользовательские CBV и как использовать CBV для обработки форм, то есть принять запросы POST.

Читать больше постов, подобных этому, на Цифровой кот

Копание просмотров на основе классов Django (серия 3 частей)

Оригинал: “https://dev.to/lgiordani/digging-up-django-class-based-views-1-1he3”