Какие функции выполняет файл views py
Представления (views), или как их ещё называют "джангисты", "вьюхи" — центральные персонажи Web-приложений на основе Django. Ваше приложение может не взаимодействовать с базой данных, может не использовать шаблоны, но views в нём будут обязательно — приложение ведь должно как-то отвечать на запросы! :)
В Django используются два вида представлений:
- Представления-функции (view functions),
- Представления-классы (class based views).
В одном проекте могут одновременно использоваться оба вида. И нельзя сказать, что какой-то один вид лучше другого по всем признакам — у обоих видов есть свои сильные и слабые стороны.
Создадим шаблон для страницы поста
Мы создадим файл post_detail.html в директории blog/templates/blog .
Он должен содержать следующее:
И снова мы расширяем base.html . В блоке content мы отображаем дату публикации (published_date, если она существует), заголовок и текст. Нам также нужно обсудить пару важных вещей, хорошо?
. — это тег шаблона, который мы можем использовать, если нам нужно что-то проверить (помнишь конструкцию if . else .. из главы Введение в Python?). В данном случае мы хотим проверить, не пуста ли дата публикации поста — published_date .
Отлично, можешь перезагрузить страницу и проверить, пропала ли ошибка Page not found .
Ура! Всё работает!
3. dispatch()
Работа метода dispatch() отражает его название:
Если же такой глагол нашёлся, диспетчер назначает соответствующий метод переменной handler (для OPTIONS → options, для GET → get , для POST → post ).
Если мы вернёмся и посмотрим полный код класса View , то увидим, что в нём предопределён только один метод options() .
Он вернёт нам ответ на запрос с заголовком Allow с поддерживаемыми методами.
Но что делать, если нам нужно обработать запрос GET?
5. TemplateResponseMixin
Имена атрибутов информативны сами по себе (но если что вы всегда можете заглянуть в документацию).
Если вдруг вы забыли, то, наследуясь от класса TemplateView, мы переопределили имя шаблона на 'about.html' , именно этот шаблон и будет использоваться для рендера.
Точно так же вы можете переопределять остальные параметры нашего класса, чтобы получить необходимое поведение CBV. Конечно, собирать все атрибуты при множественном наследовании выматывающая работа, но здесь нам на помощь приходит сайт Classy Class-Based Views, в котором вы сразу видите все атрибуты и методы класса и его родителей. Теперь не требуется бежать на StackOverflow, чтобы нагуглить ответ, можно использовать перегрузку аттрибутов с пониманием.
В этом миксине берётся дефолтный TemplateResponse (если вы его не переопределяли), ему передаётся контекст и список шаблонов, полученный с помощью несложного метода get_template_names :
который возвращает имя шаблона внутри списка или возбуждает ошибку, если оно не определено.
И, как финальный результат, экземпляр TemplateResponse возвращается в метод get() , который далее передаёт по цепочке в dispatch() и view() , и на этом работа представления завершается.
Добавим представление для страницы поста
В этот раз представление получит дополнительный параметр pk . Но как дать нашему представлению знать о нём? Для этого мы определим функцию как def post_detail(request, pk): . Обрати внимание, что мы должны использовать то же имя переменной, что мы выбрали для обработки URL ( pk ). Пропуск переменной будет неправилен и приведёт к ошибке!
Теперь мы хотим получить одну конкретную запись из блога. Для этого потребуется использовать QuerySet:
Однако в этом коде есть проблема. Если не существует экземпляра объекта Post с заданным primary key ( pk ), мы получим страшную ошибку!
Мы этого не хотим! Однако в Django, конечно, есть средство, которое позволит нам её обойти: get_object_or_404 . В случае, если не существует экземпляра объекта Post с заданным pk , мы получим намного более приятную страницу (которая называется Page Not Found 404 ).
Хорошая новость состоит в том, что ты можешь сделать свою страницу Page not found . Но для нас сейчас это не самая важная задача, и мы её пропустим.
Хорошо, пришло время добавить представление в файл views.py !
В файле blog/urls.py мы создали шаблон URL под названием post_detail , который ссылался на представление под названием views.post_detail . Это значит, что Django ожидает найти функцию-представление с названием post_detail в blog/views.py .
Нам нужно открыть файл blog/views.py и добавить в него следующий код:
— рядом с другими строками, начинающимися с from . В конец же файла мы добавим наше новое представление:
Заработало! Только что произойдёт, если ты попробуешь перейти по ссылке из заголовка записи?
Ой, нет! Другая ошибка! Но мы уже знаем, как иметь с ней дело, верно? Нам нужно добавить шаблон!
3.6. Создание Шаблона
Сейчас, определив URL для нашего представления списка контактов, мы можем испробовать его. Django включает в себя сервер подходящий для целей разработки, который вы можете использовать для тестирования вашего проекта:
Примечание переводчика:
localhost указывайте в том случае, если запускаете браузер с того же хоста, где запущен сервер. Если сервер у вас запущен на другом хосте (как у меня) — вместо localhost укажите IP адрес этого хоста (в моем случае это 192.168.1.51 ).
По умолчанию, Django ищет шаблоны в приложениях, так же как и в директориях, указанных в settings.TEMPLATE_DIRS . Общие представления ожидают, что шаблоны найдутся в директории приложения (в данном случае в директории contacts ), и имя файла будет содержать имя модели (в данном случае ожидаемое имя файла: contact_list.html ). Это приходится кстати, когда вы разрабатываете приложения для повторного использования: пользователь вашего приложения может создать свои шаблоны, которые перекроют шаблоны по умолчанию, и они будут хранится в директории, прямо связанной с приложением.
Примечание переводчика:
Django ожидает, что искомый шаблон находится по адресу имя_приложения/templates/имя_приложения/имя_шаблона
Для наших целей, однако, нам не нужен дополнительный слой из структур директорий, так что мы определим шаблон явно, использую свойство template_name нашего представления-класса. Давайте добавим одну строчку в views.py :
Создадим в директории contacts (это директория с приложением) поддиректорию templates , а в ней создадим файл шаблона contact_list.html :
3.7. Создаем контакты
Добавление информации в базу данных через интерактивную оболочку занимает слишком много времени, так что давайте создадим представление для добавления новых контактов.
Так же как и в случае с выводом списка контактов, воспользуемся одним из общих представлений Django. В файле views.py мы добавим несколько строчек:
Примечание переводчика:
Если вы используете Django версии >= 1.7, то можете добавить к классу CreateContactView дополнительное поле:
Это не обязательно, но с версии Django 1.7 неиспользование этого поля в классах с автоматическим генерированием форм объявлено устаревшим (при выполнении тестов вам об этом сообщат). Если вы его не укажете — то в форме редактирования будут использоваться все поля, но с версии Django 1.8 такое поведение будет удалено.
Примечание: Контекстные переменные в представлениях-классах
Набор переменных доступных в шаблоне, когда он выводится, называется Контекстом . Контекст — это комбинация данных из представления и информации из процессоров контекста .
Когда вы используете встроенные общие представления, не совсем очевидно какие переменные доступны в контексте. Со временем вы откроете для себя, что их имена (предоставляемые общими представлениями в контекст шаблона) достаточно последовательны — form , object и object_list часто используются — хотя это не поможет вам в начале пути. К счастью, документация по этому вопросу очень похорошела с версии Django 1.5.
В представлениях-классах метод get_context_data() используются для добавления информации в контекст. Если вы перегрузите этот метод, вам нужно будет разрешить **kwargs и вызвать суперкласс.
Шаблон добавления контакта будет немного более сложный, чем шаблон списка контактов, но не слишком. Наш шаблон contacts/templates/edit_contact.html будет выглядеть как то так:
Для новичка, который осваивает Django, представления на основе классов больше похожи на магию чёрного ящика, по крайней мере, у меня при первом знакомстве сложилось именно такое впечатление. Обильные руководства зачастую показывают, какие атрибуты и методы следует определить в вашем классе, чтобы этот ящик работал на вас, но не дают понимания принципа работы.
Я хочу залезть под капот фреймворка и строчка за строчкой разобрать, как же работают представления на основе классов. Надеюсь, что по прочтении, Class-based views уже не будут казаться такими пугающими и я подстегну вас к дальнейшему самостоятельному изучению исходников. Возможно, вы думали о фреймворке как о некой магии, которую невозможно понять, но на самом деле это обычный код, написанный опытными разработчиками.
Шаблон
Нам нужно создать файл post_edit.html в директории blog/templates/blog . Чтобы заставить форму работать, нам потребуется несколько вещей:
- Нам нужно отобразить форму. Мы можем сделать это, к примеру, простым > .
- Строка выше должна быть обёрнута в HTML-теги
- Нам потребуется кнопка Save . Мы добавим её при помощи HTML-кнопки:
- И, наконец, сразу после открытия тега < form. >мы должны добавить . Это очень важно, поскольку так мы делаем форму защищённой! Django будет ругаться, если ты забудешь добавить этот код:
Хорошо, давай посмотрим, как должен выглядеть HTML-код в файле post_edit.html :
Время обновить страницу! Ура! Форма отображается!
Но подожди минутку! Если ты наберёшь что-нибудь в полях title и text и попробуешь сохранить — что произойдёт?
Ничего! Мы снова на той же странице и наш текст пропал. и новая запись не была добавлена. Так что же пошло не так?
Ответ прост: ничего. Нам нужно сделать кое-что ещё, чтобы новое представление заработало.
Сохраняем данные из формы
Снова открой файл blog/views.py . Всё, что у нас есть в представлении post_new , выглядит пока следующим образом:
После отправки формы мы возвращаемся к тому же представлению, но в этот раз с новыми данными в request , а точнее, в request.POST (имя POST не имеет ничего общего с "постом" в блоге, оно связано с тем, что мы "публикуем" данные). Помнишь, что в HTML-файле определение имеет параметр method="POST" ? Все поля формы теперь находятся в request.POST . Ты не должна переименовывать POST во что-то другое (другое доступное значение параметра method — GET , но у нас сейчас нет времени объяснять разницу).
Получается, что в представлении view нам нужно обработать две разные ситуации. Первая: когда мы только зашли на страницу и хотим получить пустую форму. Вторая: когда мы возвращаемся к представлению со всей информацией, которую мы ввели в форму. Таким образом, нам потребуется ввести условие (для этого мы будем использовать условный оператор if ):
Теперь заполним строку, занятую [. ] . Если method — POST , тогда мы хотим построить PostForm с данными из формы, верно? Мы добьёмся этого следующим образом:
Легко! Дальше мы проверим, корректна ли форма (все ли необходимые поля заполнены и не отправлено ли некорректных значений). Мы сделаем это при помощи form.is_valid() .
Мы проверяем, допустимо ли содержимое формы, и, если всё в порядке, сохраняем её!
Фактически мы выполняем две операции: сохраняем форму form.save и добавляем автора (поскольку обязательного поля author нет в PostForm !). commit=False означает, что мы пока не хотим сохранять модель Post — сначала нужно добавить автора. В основном ты будешь использовать form.save() , без commit=False , но в данном случае нам это пригодится. post.save() сохранит изменения (после добавления автора), и новая запись будет создана!
Наконец, будет прекрасно, если мы сможем сразу переходить к странице post_detail после добавления новой записи, согласна? Для этого нам понадобится еще один импорт:
Добавь эту строку в начало файла. Теперь мы можем сделать переадресацию на страницу post_detail для созданной записи:
post_detail — это имя представления, которое нам необходимо. Помнишь, что это представление требует переменную pk ? Чтобы передать её представлению, мы используем аргумент pk=post.pk , где post — это новая запись в блоге!
Хорошо, мы многое обсудили, пора взглянуть на представление полностью, верно?
Возможно, ты заметила, что мы устанавливаем дату публикации перед сохранением поста. В последствии мы сделаем кнопку публикации в Django Girls Tutorial: Extensions.
Создадим URL для страницы поста
Давай создадим в urls.py URL для представления post_detail !
Давай создадим URL в файле blog/urls.py и укажем Django на представление под названием post_detail , которое будет отображать пост целиком. Добавь строчку path('post//', views.post_detail, name='post_detail') в файл blog/urls.py . Файл должен выглядеть так:
Фрагмент post// определяет шаблон URL-адреса. Сейчас мы его поясним:
- post/ значит, что после начала строки URL должен содержать слово post и косую черту /. Пока всё в порядке.
- — эта часть посложнее. Она означает, что Django ожидает целочисленное значение и преобразует его в представление — переменную pk .
- / — затем нам нужен еще один символ / перед тем, как адрес закончится.
Помнишь, каким должен быть следующий шаг? Конечно: добавить представление!
Безопасность
Круто иметь возможность создавать новые посты, просто перейдя по ссылке! Однако сейчас кто угодно из посетителей твоего сайта может создать новую запись в блоге, а это, скорее всего, совсем не то, чего бы тебе хотелось. Давай сделаем так, чтобы кнопка показывалась для нас, а не кого-либо ещё.
В файле blog/templates/blog/base.html найди page-header div и тег , который мы добавили ранее. Должно выглядеть примерно так:
Мы добавим сюда ещё один тег , чтобы ссылка показывалась только пользователям, вошедшим в админку. То есть пока что — только тебе! Измени тег , чтобы получилось так:
Из-за этого ссылка будет отправлена в браузер, только если запрашивающий страницу пользователь вошёл в систему. Это не обезопасит создание новых постов полностью, но для начала и это неплохо. Мы подробнее рассмотрим вопросы безопасности в дополнении к учебнику.
Помнишь иконку редактирования, которую мы добавили на страницу поста? Чтобы посторонние не смогли менять уже созданные посты, нам нужно изменить страничку похожим образом.
Открой файл blog/templates/blog/post_detail.html и найди такую строку:
Замени её на следующее:
Поскольку ты авторизована, никаких изменений после обновления страницы ты не увидишь. Но попробуй загрузить страницу в другом браузере или в режиме инкогнито, и увидишь, что ссылка не отобразится!
Представление post_new
Самое время открыть файл blog/views.py и добавить следующую строку к остальным, начинающимся с from :
А затем наше представление:
Чтобы создать новую форму Post , нам потребуется вызвать PostForm() и передать её шаблону. Мы ещё вернёмся к этому представлению, а пока давай быстро создадим шаблон под форму.
Представления-функции
И раз представление — это обычная функция, к ней можно применять обычные же декораторы! В Django есть несколько полезных. Вот один из них:
Если такая view получит запрос с отличным от указанных методом, то автоматически будет сформирован ответ ResponseNotAllowed (код 405).
View function очень просты концептуально и дают вам полный контроль над обработкой запроса. Это, безусловно, полезно, но заставляет каждый раз писать код вручную. Или подготавливать библиотечку декораторов, упрощающих решение типичных задач.
Заключение
Конечно, разобрав один из наиболее простых CBV сложно сказать, что уверенно ими владеете, впереди вас ждут более интересные Generic display views, такие как DetailView и ListView с более сложными миксинами и разветвлённым наследованием, но хочется верить, что, прочитав этот материал, вы сможете разобраться в них самостоятельно.
А пока давайте подведём итог полученным знаниям:
CBV базируется на множестве классов и миксинов, но во главе стоит класс View с конструктором экземпляра и методом as_view() .
Вызов метода as_view() в URLConf возвращает нам функцию view() , которую Django будет вызывать при совпадении адреса с паттерном
Вызов функции view() создаёт экземпляр представления и запускает цепочку обработки запроса
В конце цепочки методов-обработчиков нам возвращается экземпляр TemplateResponse , как результат выполнения представления
Ссылка на страницу с формой
Пришло время открыть файл blog/templates/blog/base.html . Мы добавим ссылку в элемент div с именем page-header :
Обрати внимание, что мы назвали новое представление post_new . Класс glyphicon glyphicon-plus определён в используемой нами теме bootstrap — таким образом мы выведем значок плюса.
После добавления строки твой html-файл должен выглядеть следующим образом:
Нам нужно открыть файл blog/urls.py и добавить строку:
Окончательная версия файла будет выглядеть следующим образом:
После перезагрузки веб-сайта мы увидим ошибку AttributeError , поскольку представление post_new не реализовано. Давай добавим его прямо сейчас.
Создадим в шаблоне ссылку на страницу поста
Мы начнём с добавления ссылки внутри файла blog/templates/blog/post_list.html . Пока он выглядит следующим образом:
Самое время разобраться с загадочным . Как можешь предположить, синтаксис означает использование тегов шаблонов Django. На этот раз мы используем тот, что создаст для нас URL!
Параметр post_detail означает, что Django будет искать URL с именем post_detail в файле blog.urls.py .
А что насчёт pk=post.pk ? pk — это сокращение от primary key (первичный ключ). Он уникальным образом определяет каждую запись в базе данных. Поскольку мы не задали первичного ключа в нашей модели Post , Django создал такой ключ за нас (по умолчанию это порядковый номер, то есть 1, 2, 3…) и добавил поле pk к каждой записи блога. Для получения первичного ключа мы напишем post.pk — точно так же, как мы получали значения остальных полей ( title , author и т.д.) нашего объекта Post .
Валидация формы
Теперь мы покажем тебе, насколько круты формы в Django. Запись в блоге должна иметь поля title и text . В нашей модели Post мы не указываем, что эти поля необязательны (в отличие от published_date ), так что Django по умолчанию будет ожидать, что пользователь их заполнит.
Попробуй сохранить форму с незаполненными полями title и text . Угадай, что произойдёт!
Django заботится о проверке всех полей в нашей форме на корректность. Разве не шикарно?
0. URL dispatcher
Давайте посмотрим, как бы выглядел urlpatterns на основе привычного Function-based View (FBV) и на Class-based View (CBV):
Исходный код класса TemplateView
Откуда же он взялся? Для ответа на этот вопрос следует рассмотреть всю иерархию наследования AboutView .
Полезные ссылки
Classy Class-Based Views — ресурс, позволяющий для каждого CBV увидеть все наследуемые атрибуты и методы
P.S.: На написание этой статьи меня вдохновил пост в блоге Django Deconstructed.
Ещё одна вещь: развёртывание!
Было бы неплохо проверить, что веб-сайт всё ещё будет работать на PythonAnywhere, верно? Давай еще раз проведём развёртывание.
И нажми Reload на вкладке Web.
Форма редактирования
Теперь мы знаем, как добавить новую форму. Но что, если мы хотим внести исправления в уже существующую запись? По сути это схожая с предыдущей задача. Давай быстро создадим пару важных вещей (если ты чего-то не понимаешь, спроси своего тренера или загляни в предыдущие главы, поскольку мы уже объясняли все необходимые шаги).
Открой blog/templates/blog/post_detail.html и добавь следующую строку:
так, чтобы шаблон выглядел следующим образом:
В файле blog/urls.py добавь:
Мы будем использовать повторно шаблон blog/templates/blog/post_edit.html , так что осталось лишь отсутствующее представление.
Давай откроем файл blog/views.py и добавим в самый конец следующее:
Выглядит практически идентично представлению post_new , верно? Но не совсем. Во-первых, мы передаём параметр pk из URL-адреса. Кроме того, мы получаем модель Post для редактирования при помощи get_object_or_404(Post, pk=pk) и передаём экземпляр post в качестве instance форме и при сохранении…
… и когда мы открываем форму для редактирования:
Хорошо, давай удостоверимся, что всё работает! Перейди на страницу post_detail . Ты должна увидеть кнопку редактирования в правом верхнем углу:
Когда ты её нажмёшь, то увидишь форму с выбранной записью:
Поменяй заголовок и текст, а затем сохрани запись!
Поздравляем! Твое приложение становится всё более сложным!
3.4. Вывод перечня контактов
Мы начнем с представления, которое выводит список контактов из базы данных.
Базовая реализация представления очень коротка. Мы можем написать его всего-лишь в несколько строк. Для этого в файле views.py нашего приложения contacts наберем следующий код:
4. get()
На этом моменте полномочия базового класса View всё :) и в игру вступает его наследник TemplateView , в котором нужный метод определён:
Получая знакомые уже нам атрибуты, класс формирует контекст для шаблона, вызывая метод get_context_data из примеси ContextMixin .
Миксин не занимается rocket science, а всего лишь берёт словарь ключевых аргументов, полученных из URL адреса, добавляет туда ключ 'view' , который ссылается на наш экземпляр класса (таким образом вы сможете обратиться к экземпляру класса прямо из шаблона), и под конец примешивает словарь extra_context , если вы вдруг его переопределяли.
Получив контекст, TemplateView может его отрендерить при помощи примеси TemplateResponseMixin и её метода render_to_response .
3.3. Представления-классы (CBV)
1. Class View
Иерархия наследования класса AboutView
Давайте посмотрим на исходный код 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 можно было заменить следующим выражением:
Смотрим код дальше. В цикле for перебираются ключи initkwargs , которые проходят две проверки:
Вторая проверка разрешает нам переопределять только известные атрибуты и методы класса:
Далее по коду мы встречаемся с функцией 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 .
2. View function
Если описать коротко, то именно функция 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 есть атрибут запроса:
По итогу функция возвращает нам результат выполнения следующего метода - dispatch() .
Background
Я предполагаю, что у читателя есть базовое представление об ООП в Python и опыт создания проекта на Django. Для более комфортного чтения рекомендую также познакомиться со следующими темами:
В качестве представления на основе класса я возьму абстрактный AboutView , наследника TemplateView , и на этом примере рассмотрю жизнь класса: классы-предки, формирование функции конструктора, вызов из URLConf, примеси и внутреннюю логику работы.
Несмотря на то, что я старался максимально подкрепить мыслительный процесс исходным кодом, я понимаю, что держать в голове нить повествования может быть сложно. Для облегчения задачи я создал блок-схему, на которой можно увидеть все атрибуты и методы класса, откуда они наследуются, и окинуть процесс взаимодействия методов между собой одним взглядом.
И последнее: публикация!
Теперь давай посмотрим, как это будет работать на PythonAnywhere. Пришло время для очередного развёртывания!
- Сначала нам нужно сделать commit и push нового кода в репозиторий GitHub:
(Не забудь подставить вместо свой поддомен на PythonAnywhere без угловых скобок.)
Представления-классы
Все представления этого вида наследуются от класса django.views.View . Так выглядит код в простейшем случае:
Метод get здесь работает точь-в-точь как view function. При этом на каждый запрос будет создан новый экземпляр этого класса, так что вы смело можете объявлять в классе методы, которые по ходу выполнения запроса будут менять его состояние.
Регистрируется представление-класс с помощью метода (метода класса) as_view . Выглядит регистрация так:
Чем же представления-классы хороши? Возможностью лёгкого переиспользования поведения через наследование. Взглянем на встроенный TemplateView из модуля django.views.generic.base в деле:
Нам даже не пришлось наследовать класс, мы просто использовали готовый, указав при регистрации имя шаблона!
Но даже если бы мы унаследовали класс, чтобы передать шаблону какие-то данные (в контексте), то нам бы пришлось переопределить лишь малую часть функциональности класса-предка:
И подобных базовых представлений (base views) Django содержит предостаточно! Особенно хорошо проработаны представления для отображения сущностей из базы данных: здесь вам и отображение списков записей, и отображение отдельных записей в детализированной форме. Сказывается направленность Django на решение задач по разработке контентных сайтов.
Представления-классы хорошо подходят для решения повторяющихся задач. Большая часть из которых, к тому же, уже "почти решена" силами Django.
Мы уже выполнили часть необходимых шагов для создания веб-сайта: мы знаем как создать модель, URL, представление и шаблон. Мы также знаем, как улучшить визуальный дизайн с помощью CSS.
Время для практики!
Первое, что нам потребуется в блоге — страница для отображения конкретной записи, верно?
У нас уже есть модель Post , так что нам не нужно добавлять дополнительный код в файл models.py .
Обновим статические файлы на сервере
Серверы вроде PythonAnywhere часто обрабатывают статические файлы (например, CSS) не так, как Python-файлы. Так происходит потому, что сервера могут оптимизировать их использование так, чтобы они быстрее загружались. В результате после того, как мы поменяли CSS-файлы, надо дать серверу команду обновить их. Эта команда называется collectstatic .
Начни с активации virtualenv, если окружение уже не активно (PythonAnywhere использует для этого команду workon . Она работает так же, как source myenv/bin/activate , которую ты используешь на своём компьютере.
Команда manage.py collectstatic немножко похожа на manage.py migrate . Мы сперва вносим какие-то изменения в наш код, а затем сообщаем Django применить эти изменения — к набору статических файлов на сервере или к базе данных.
Последним, что нам стоит сделать для нашего веб-сайта, является удобный способ добавления и редактирования записей. admin -панель Django удобна, но её дизайн сложно изменять. С forms (формами) у нас будет абсолютная власть над интерфейсом блога — мы сможем сделать практически всё, что только можно придумать!
Формы Django удобны тем, что мы можем создать новую форму с нуля или воспользоваться ModelForm для сохранения содержимого формы в модель.
Это как раз то, что нам нужно сделать: мы создадим форму для модели Post .
Как и любая важная часть Django, формы имеют свой собственный файл: forms.py .
Нам нужно создать файл с таким именем в директории blog .
Теперь открой его и набери следующее:
Для начала нам нужно импортировать формы Django ( from django import forms ) и, разумеется, нашу модель Post ( from .models import Post ).
PostForm , как ты, вероятно, подозреваешь, — это имя для нашей формы. Нам нужно также сообщить Django, что эта форма относится к ModelForm (чтобы он смог поколдовать для нас) — forms.ModelForm поможет с этим.
Дальше у нас class Meta , где мы определяем, какая модель будет использоваться для создания формы ( model = Post ).
В завершение мы можем указать, какие поля должны присутствовать в нашей форме. Сейчас нам требуются только поля title и text — author будет автоматически выбран в зависимости от авторизованного пользователя (тебя), а created_date должна автоматически проставляться в момент создания записи (т.е. через код), верно?
Вот и всё! Теперь мы можем использовать форму в представлении и отобразить её в шаблоне.
Поэтому снова нам необходимо создать ссылку на страницу, URL-адрес, представление и шаблон.
3.5. Определяем URL'ы
Конфигурация URL (URLconf) указывает Django как по адресу запроса найти ваш Python-код. Django смотрит конфигурацию URL, которая определена в переменной urlpatterns файла urls.py .
Давайте добавим в файл addressbook/urls.py URL-шаблон для нашего представления, которое отображает список контактов:
- использование функции url() не является строго обязательным, но я предпочитаю использовать ее: когда вы начнете добавлять больше информации в URL-шаблоны, она позволит вам использовать именованные параметры, делая код более чистым;
- первый параметр принимаемый функцией url() — это регулярное выражение. Обратите внимание на замыкающий символ $ ; как думаете, почему он важен?
- вторым параметром указывается вызываемое представление. Это может быть как непосредственно вызываемый объект (импортированный вручную), так и строка описывающая его. Если это строка, то в случае соответствия URL-шаблона строке запроса, Django сам импортирует необходимый модуль (до последней точки), и вызовет последний сегмент строки (после последней точки);
- замете, что когда мы используем представление-класс, мы обязаны использовать реальный объект, а не строку описывающую этот объект. Мы должны так делать из за того, что мы вызываем метод класса as_view() . Этот метод возвращает обертку над нашим классом, которую может вызвать диспетчер URL Django;
- имя, данное URL-шаблону, позволят вам делать обратный поиск ;
- имя URL полезно, когда вы ссылаетесь из одного представления на другое, или выполняете перенаправление, так как вы можете управлять структурой URL'ов из одного места.
3.1. Основы представлений
Конечно, как и большинство других фреймворков, Django позволяет вам передавать аргументы в представление через URL. Мы поговорим об этом, когда будем строить наше приложение.
3.2. Общие представления и представления-классы
Читайте также: