Uploaded by Егор Киселев

Django for beginners Build websites with Python & Django Rus

advertisement
Django для начинающих
Научитесь веб-разработки с Django 2.0
William S. Vincent
© 2018 William S. Vincent
Группа в ВК "Django_Python"
Содержание
Введение
Почему Django
Почему эта книга
Структура книги
Макет книги
Вывод
1
1
3
3
5
7
Глава 1: Первоначальная Настройка
Командная строка
Установка Python 3 на Mac OS X
Установка Python 3 на Windows
Установка Python 3 на Linux
Установка Виртуальных Среды
Джанго
Установить Git
Текстовой редактор
Вывод
8
8
11
13
14
15
16
20
21
21
Глава 2: Hello World приложение
Начальная настройка
Создание приложения
Views и URL конфигурация
Привет мир!
Git
Bitbucket
Вывод
22
22
25
27
30
31
33
37
Глава 3: Страницы приложения
Начальная настройка
Шаблоны
Основа Классов
Views URLs
Добавление страницы
39
39
41
44
45
47
Группа в ВК "Django_Python"
ОГЛАВЛЕНИЕ
Расширение Шаблонов
Тесты
Git и Bitbucket
Local vs Production
Heroku(облачная PaaS-платформа)
Дополнительный файл
Deploy(развертывание)
Вывод
49
52
54
56
57
58
61
64
Глава 4: Приложение Доска Объявлений
Начальная настройка
Создание модели базы данных
Активация моделей
Джанго Админ
Views/Templates/URLs
Добавление новых записей
Тесты
Bitbucket
Heroku конфигурация
Heroku развертывание
Выводы
65
65
68
69
70
77
81
85
90
91
93
95
Глава 5: Приложение Блог
Начальная настройка
Модель базы данных
Админ
URLs
Views
Templates
Static files
Отдельные страницы блога
Тесты
Git
Выводы
96
96
98
100
105
107
108
111
116
122
125
125
Глава 6: Формы
Формы
Обновление форм
Удаление View
Тесты
Выводы
127
127
138
145
151
155
Глава 7: Учетные Записи Пользователей
156
Группа в ВК "Django_Python"
ОГЛАВЛЕНИЕ
Вход
Обновление Домашней страницы
Ссылка "выход"
Регистрация
Bitbucket
Конфигурация Heroku
Развертывание на Heroku
Выводы
156
159
161
164
170
171
173
177
Глава 8: Пользовательская Модель
Установка
Пользовательская User Model
Формы
Суперпользователь
Выводы
178
178
180
182
185
187
Глава 9: Аутентификация Пользователя
Templates
URLs
Admin
Выводы
188
188
192
197
203
Глава 10: Bootstrap
Приложение Страницы
Тесты
Bootstrap
Форма Регистрации
Дальнейшие действия
204
204
208
211
219
224
Глава 11: смена и сброс пароля
Изменение пароля
Настройка изменения пароля
Сброс пароля
Пользовательские шаблоны
Вывод
226
226
228
231
235
240
Глава 12: Электронная Почта
SendGrid
Пользовательская эл.почта
Вывод
241
241
246
250
Глава 13: Приложение газета
Приложение Статьи
251
251
Группа в ВК "Django_Python"
ОГЛАВЛНИЕ
URLs и Views
Редактирование/Удаление
Создание страницы
Выводы
257
262
268
276
Глава 14: Права доступа и авторизация
Улучшаем CreateView
Авторизация
Mixins
Обновление views
Вывод
277
277
279
281
283
285
Глава 15: Комментарии
Model
Admin
Template
Вывод
286
286
288
295
299
Вывод
Ресурсы Джанго
Питон книги
Блоги
Обратная связь
301
302
302
303
303
Группа в ВК "Django_Python"
Введение
Добро пожаловать в Django для начинающих, проектный подход к обучению веб-разработке
с помощью веб-платформы Django. В этой книге вы создадите пять все более сложных вебприложений, начиная с простого приложения "Привет, мир", переходя к приложению блога
с формами и учетными записями пользователей, и, наконец, приложение газеты, используя
пользовательскую модель, интеграцию электронной почты, внешние ключи, авторизацию,
права доступа и многое другое.
К концу этой книги вы должны чувствовать себя уверенно, создавая свои собственные
проекты Django с нуля, используя лучшую современную практику.
Django-это бесплатный веб-фреймворк с открытым исходным кодом, написанный на языке
программирования Python и используемый миллионами программистов каждый год. Его
популярность обусловлена дружелюбием как к начинающим, так и продвинутым
программистам: Django достаточно надежен для использования крупнейшими веб–сайтами
в мире – Instagram, Pinterest, Bitbucket, Disqus, но также достаточно гибок, чтобы быть
хорошим выбором для стартапов на ранней стадии и прототипирования личных проектов.
Эта книга регулярно обновляется и содержит последние версии Django (2.0) и Python (3.6 x).
Он также использует Pipenv, который теперь официально Рекомендуемый менеджер
пакетов Python.org для управления пакетами Python и виртуальными средами. На всем
протяжении мы будем использовать лучшие современные практики сообщества Django,
Python и веб-разработки, особенно тщательное использование тестирования.
Почему Django
Веб-фреймворк - это набор модульных инструментов, которые абстрагируют большую часть
трудностей и повторений, присущих веб-разработке. Например, большинству веб-сайтов
Группа в ВК "Django_Python"
2
Introduction
нужен такой же базовый функционал: возможность подключения к базе данных, установка
URL маршрутов, отображение контента на странице, корректная защита и так далее. Вместо
того, чтобы воссоздавать все это с нуля, программисты на протяжении многих лет создавали
веб-фреймворки на всех основных языках программирования: Django и Flask в Python, Rails в
Ruby и Express в JavaScript среди многих, многих других.
Django унаследовал подход Python “batteries-included” и включает в себя поддержку из
коробки для общих задач в веб-разработке:
• Аутентификация пользователя
• Шаблоны, маршруты и представления
• Интерфейс администратора
• Надежная безопасность
• Поддержка нескольких серверных баз данных
• И многое другое
Такой подход значительно упрощает нашу работу как веб-разработчиков. Мы можем
сосредоточиться на этом, что делает наше веб-приложение уникальным, а не изобретать
колесо, когда дело доходит до стандартной функциональности веб-приложения.
Напротив, несколько популярных фреймворков–в первую очередь Flask на Python и Express
на JavaScript-используют подход “микропрограммирования”. Они предоставляют только
минимум, необходимый для простой веб-страницы, и оставляют на усмотрение
разработчика установку и настройку сторонних пакетов для репликации базовой
функциональности веб-сайта. Такой подход обеспечивает большую гибкость для
разработчика,
но
также
дает
больше
возможностей
для
ошибок.
По состоянию на 2018 Год Django находится в активной разработке более 13 лет, что делает
его седым ветераном в программных годах. Миллионы программистов уже использовали
Django для создания своих сайтов. И это, несомненно, хорошо. Веб-разработка трудна. Не
имеет смысла повторять один и тот же код–и ошибки–когда, большое сообщество
блестящих разработчиков уже решило эти проблемы для нас.
Группа в ВК "Django_Python"
3
Introduction
В то же время, Django остается в стадии активной разработки и имеет годовой график
выпуска. Сообщество Django постоянно добавляет новые функции и улучшения
безопасности. Если вы создаете сайт с нуля Джанго это отличный выбор.
Почему эта книга
Я написал эту книгу, не смотря на то, что Django очень хорошо документирован потому что
существует серьезная нехватка доступных учебников для начинающих. Когда я впервые
узнал Django несколько лет назад, я выбивался из сил пытаясь выполнять по официальному
учебнику. По этому я так хорошо помню, что думал.
С большим опытом сейчас я признаю, что авторы документации Django столкнулись с
трудным выбором: они могли бы подчеркнуть простоту использования Django или его
глубину, но не то и другое одновременно. Они выбирают последнее, и как
профессиональный Разработчик я ценю этот выбор, но как новичок я нашел это
как...разочарование!
Моя цель состоит в том, что бы эта книга заполняла пробелы и демонстрировала насколько
дружелюбен к новичкам Django.
Вам не нужен прошлый опыт Python или веб-разработки для завершения этой книги. Она
специально написан так, что даже новичок может следовать по ней и почувствовать магию
написания собственных веб-приложений с нуля. Однако, если вы серьезно относитесь к
карьере в веб-разработке, вам в конечном итоге нужно будет потратить время, чтобы
изучить Python, HTML и CSS должным образом. В заключение приводится перечень
рекомендуемых ресурсов для дальнейшего изучения.
Структура Книги
Мы начнем с правильного описания того, как настроить локальную среду разработки
в главе 1. В этой книге мы используем кропотливые инструменты: самую последнюю версию
Группа в ВК "Django_Python"
4
Introduction
Django (2.0), Python (3.6) и Pipenv для управления нашими виртуальными средами. Мы также
пройдем введение в командную строку и обсудим как работать с современным текстовым
редактором.
В Главе 2 мы создадим наш первый проект, минимальное Hello, World приложение, которое
демонстрирует, как настроить новые проекты Django. Так как создание хорошего
программного обеспечения важно, мы также сохраним нашу работу в git и загрузим копию в
удаленный репозиторий кода на Bitbucket.
В Главе 3 мы создадим, протестируем и развернем Приложение Pages, которое
представляет шаблоны и view на основе классов. Шаблоны это то, как Django позволяет
создавать (Не Повторяйтесь - принцип разработки программного обеспечения, нацеленный
на снижение повторения информации различного рода) разработку с помощью HTML и CSS,
в то время как view на основе классов требуют минимального количества кода для
использования и расширения основной функциональности в Django. Они потрясающие, вы
это скоро увидите. Мы также добавим наши первые тесты и развернем в Heroku, который
имеет свободный уровень и который мы будем использовать на протяжении всей этой
книги. Использование таких поставщиков услуг, как Heroku, превращает разработку из
болезненного, трудоемкого процесса во что-то, что занимает всего несколько щелчков
мыши.
В Главе 4 мы создадим наш первый проект с базой данных, приложение для доски
объявлений. Django предоставляет мощный ORM, который позволяет нам писать сжатый
Python для наших таблиц базы данных. Мы рассмотрим встроенное приложение
администратора, которое обеспечивает графический способ взаимодействия с нашими
данными и может быть даже использовано в качестве системы управления контентом (CMS),
аналогичной Wordpress. Также мы напишем тесты для всего нашего кода, сохраним
удаленную копию на Bitbucket и развернем в Heroku. Наконец, в Главах 5-7 мы готовы к
нашему финальному проекту: надежному приложению для блога, которое демонстрирует,
как выполнять функциональность CRUD (Create-Read-Update-Delete)(Создание-ЧтениеОбновление-Удаление) в Django. Мы обнаружим, что общие view на основе классов Django
означают, что для этого нам нужно написать лишь небольшое количество реального кода!
Затем мы добавим формы и интегрируем встроенную систему аутентификации
пользователей Django (login, logout, signup).
В Главе 8 мы начнем сайт газеты и введем понятие пользовательских моделей, Django
лучшая практика, которая редко рассматривается в учебных пособиях. Проще говоря все
новые
Группа в ВК "Django_Python"
5
Introduction
проекты должны использовать пользовательскую модель, и в этой главе вы узнаете, как это
сделать. Глава 9 охватывает аутентификацию пользователей, Глава 10 добавляет Bootstrap
для стилизации, а главы 11-12 реализуют сброс пароля и изменение по электронной почте.
В главах 13-15 мы добавляем статьи и комментарии к нашему проекту, а также
соответствующие разрешения и полномочия. Мы даже узнаем некоторые приемы для
настройки администратора, чтобы отобразить наши растущие данные.
В заключении дается обзор основных понятий, введенных в книгу, и список рекомендуемых
ресурсов для дальнейшего обучения.
Хотя вы можете выбирать главы для чтения, структура книги очень продумана. Каждое
приложение / глава вводит новую концепцию и усиливает прошлое обучение. Я
настоятельно рекомендую прочитать его по порядку, даже если вы хотите пропустить
перейдя вперед. Более поздние главы не будут охватывать предыдущий материал в той же
глубине, что и предыдущие главы.
К концу этой книги вы будете иметь представление о том, как работает Django, возможность
создавать приложения самостоятельно, и основу необходимую, чтобы в полной мере
воспользоваться дополнительными ресурсами для изучения промежуточных и передовых
методов Django.
Макет книги
В этой книге есть много примеров кода, которые обозначаются следующим образом:
Code
# This is Python code
print(Hello, World)
Для краткости будем использовать точки ... для обозначения существующего кода, который
остается неизменным, например, в функции, которую мы обновляем.
Группа в ВК "Django_Python"
6
Introduction
Code
def make_my_website:
...
print("All done!")
Мы также часто будем использовать консоль командной строки (начиная с главы 1:
Начальная настройка для выполнения команд, которые принимают форму префикса $ в
традиционном стиле Unix.
Command Line
$ echo "hello, world"
Результатом этой конкретной команды является следующая строка:
Command Line
"hello, world"
Обычно мы объединяем команду и ее вывод. Команда всегда будет после символа $, а
выходные данные-нет. Например, команда и результат выше будут представлены
следующим образом:
Command Line
$ echo "hello, world"
hello, world
Полный исходный код всех примеров можно найти в официальном репозитории github.
Группа в ВК "Django_Python"
7
Introduction
Заключение
Django-отличный выбор для любого разработчика, который хочет создавать современные,
надежные веб-приложения с минимальным количеством кода. Он популярен, находится в
стадии активной разработки и тщательно протестирован крупнейшими веб-сайтами в мире.
В следующей главе мы узнаем, как настроить компьютер для разработки Django.
Группа в ВК "Django_Python"
Глава 1 : Начальная настройка
В этой главе описывается, как правильно настроить компьютер для работы с Django
проектом. Мы начнем с обзора командной строки и используем ее для установки последних
версий Django (2.0) и Python (3.6 x). Затем мы обсудим виртуальные среды, git и работу с
текстовым редактором.
К концу этой главы вы будете готовы создавать и изменять новые проекты Джанго за
несколько кликов.
Командная строка
Командная строка-это мощное текстовое представление компьютера. Как разработчики мы
будем использовать его широко на протяжении всей этой книги, чтобы установить и
настроить каждый проект Django.
На Mac командная строка находится в программе Terminal, расположенной в каталоге /
Applications / Utilities. Чтобы найти его, откройте новое окно Finder, откройте папку
Applications, прокрутите вниз, чтобы открыть папку Utilities, и дважды щелкните приложение
под названием Terminal.
В Windows есть встроенная программа командной строки, но это трудно использовать. Я
рекомендую вместо этого использовать Babun, бесплатную программу командной строки с
открытым исходным кодом. На главной странице сайта Babun нажмите кнопку "Загрузить
сейчас", дважды щелкните загруженный файл, чтобы установить Babun, и по завершении
перетащите установщик в корзину. Чтобы использовать Babungo в меню Пуск, выберите
программы, и нажмите на Babun.
Забегая вперед, когда книга ссылается на” командную строку", это означает открыть новую
консоль на вашем компьютере с помощью терминала или Babun.
Группа в ВК "Django_Python"
9
Chapter 1: Initial Setup
Хотя есть много возможных команд, которые мы можем использовать, на практике есть
шесть наиболее часто используемых в разработке Django.
• cd (изменить каталог)
• cd .. (перейти в верх)
• ls (список файлов в текущем каталоге)
• pwd ( вывести текущий каталог)
• mkdir (создать каталог)
• touch (создать новый файл)
Откройте командную строку и попробуйте их. Знак $ dollar-это наша командная строка: все
команды в этой книге предназначены для ввода после $.
Например, предположим, что вы находитесь на Mac, давайте перейдем в каталог рабочего
стола.
Command Line
$ cd ~/Desktop
Обратите внимание, что наше текущее местоположение
/ Desktop автоматически
добавляется перед командной строкой. Чтобы убедиться, что мы находимся в правильном
месте, мы можем использовать pwd, который распечатает путь к нашему текущему
каталогу.
Command Line
~/Desktop $ pwd
/Users/wsv/desktop
На моем компьютере Mac это показывает, что я использую пользователя wsv и нахожусь на
рабочем столе для этой учетной записи.
Давайте создадим новую папку каталога с mkdir, cd и добавим в нее новый файл index.html.
Группа в ВК "Django_Python"
10
Chapter 1: Initial Setup
Command Line
~/Desktop $ mkdir new_folder
~/Desktop $ cd new_folder
~/Desktop/new_folder $ touch index.html
Теперь используйте ls для вывода списка всех текущих файлов в нашем каталоге. Вы увидите
только что созданный index.html.
Command Line
~/Desktop/new_folder $ ls
index.html
В качестве последнего шага вернитесь в каталог рабочего стола cd .. и используйте pwd для
подтверждения местоположения.
Command Line
~/Desktop/new_folder $ cd ..
~/Desktop $ pwd
/Users/wsv/desktop
Продвинутые разработчики могут с легкостью использовать клавиатуру и командную строку
для навигации по компьютеру ; с практикой этот подход станет намного быстрее, чем с
помощью мыши.
В этой книге я дам вам точные инструкции для выполнения, вам не нужно быть экспертом в
командной строке и со временем это будет хороший навык для любого профессионального
разработчика программного обеспечения. Два хороших бесплатных ресурса для
дальнейшего изучения-это Command Line Crash Course и CodeCademy’s Course on the
Command Line.
Группа в ВК "Django_Python"
11
Chapter 1: Initial Setup
Ниже приведены инструкции для компьютеров Mac, Windows и Linux.
Установка Python 3 на Mac OS X
Хотя Python 2 установлен по умолчанию на компьютерах Mac, Python3 в нем нет. Вы можете
подтвердить это, набрав python --version в консоли командной строки и нажав Enter:
Command Line
$ python --version
Python
. .
Чтобы проверить, установлен ли Python 3, попробуйте выполнить ту же команду, используя
python3 вместо python.
Command Line
$ python
--version
Если ваш компьютер выводит �.�.x ((любая версия 3.6 или выше), то у вас все в порядке,
однако, скорее всего, вы увидите сообщение об ошибке, так как нам нужно установить
Python 3 непосредственно.
Наш первый шаг-установить пакет Xcode от Apple, поэтому выполните следующую
команду, чтобы установить его:
Группа в ВК "Django_Python"
12
Chapter 1: Initial Setup
Command Line
$ xcode-select --install
Щелкните по всем командам подтверждения (Xcode - это большая программа, поэтому для
установки может потребоваться некоторое время, в зависимости от вашего интернетсоединения).
Затем установите менеджер пакетов Homebrew через длинную команду ниже:
Command Line
$ /usr/bin/ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/inst\
all/master/install)"
Чтобы проверить правильность установки Homebrew, выполните следующую команду:
Command Line
$ brew doctor
Your system is ready to brew.
И что бы установить последнюю версию Python, выполните следующую команду:
Command Line
$ brew install python
Сейчас мы проверим, какая версия была установлена:
Группа в ВК "Django_Python"
13
Chapter 1: Initial Setup
Command Line
$ python
Python
--version
. .
Чтобы открыть интерактивную оболочку Python 3 (это позволит нам запускать команды
Python прямо на нашем компьютере )просто введите python3
:
Command Line
$ python
. .
Python
[GCC
. .
(default, Jan
Compatible Apple LLVM
,
:
:
)
. .
(clang-
. .
. )] on darwin
Type "help", "copyright", "credits" or "license" for more information.
>>>
Для выхода из интерактивной оболочки Python 3 в любое время нажмите Controld (клавиши” Control “и” d " одновременно).
Вы все еще можете запускать оболочки Python с Python 2, просто набрав python:
Command Line
$ python
Python
[GCC
. .
. .
(default, Dec
,
:
:
)
Compatible Apple LLVM
. .
(clang-
. .
. )] on darwin
Type "help", "copyright", "credits" or "license" for more information.
Установка Python 3 на Windows
Python не включен по умолчанию в Windows, однако мы можем проверить, существует ли
какая-либо версия в системе. Откройте консоль командной строки, введя cmd в меню Пуск
(Поиск Windows))
Группа в ВК "Django_Python"
14
Chapter 1: Initial Setup
Или вы можете удерживать клавишу SHIFT и щелкнуть правой кнопкой мыши на рабочем
столе, а затем выбрать «Открыть командное окно» здесь или - "Открыть окно PowerShell
здесь" в windows 10.
Введите следующую команду и нажмите Enter:
Command Line
python --version
Python
. .
Если вы видите такой вывод, Python уже установлен. Но скорее всего, этого не будет!
Чтобы загрузить Python 3, перейдите в раздел загрузки официального сайта Python.
Загрузите установщик и убедитесь, что вы выбрали опцию Add Python to PATH , которая
позволит использовать python прямо из командной строки. В противном случае мы должны
были бы ввести полный путь нашей системы и изменить наши переменные среды вручную.
После установки Python выполните следующую команду в новой консоли командной
строки:
Command Line
python --version
Python
. .
Если это сработало, вы закончили!
Установка Python 3 на Linux
Добавление Python 3 в дистрибутив Linux требует немного больше работы. Здесь
рекомендуются последние руководства для Centos и Debian. Если вам нужна
Дополнительная помощь в добавлении Python к вашему пути, обратитесь к этому ответу
StackOverflow.
Группа в ВК "Django_Python"
15
Chapter 1: Initial Setup
Виртуальная среда
Виртуальные среды являются неотъемлемой частью программирования Python. Они
представляют
собой
изолированный
контейнер,
содержащий
все
зависимости
программного обеспечения для данного проекта. Это важно, потому что по умолчанию
программное обеспечение, такое как Python и Django, установлено в одном каталоге. Это
приводит к проблеме, когда требуется работать над несколькими проектами на одном
компьютере. Что делать, если проект использует Django 2.0, но ProjectB с прошлого года все
еще находится на Django 1.10? Без виртуальных сред это становится очень трудно; с
виртуальными средами это вообще не проблема.
Есть много областей разработки программного обеспечения, которые горячо обсуждаются,
но использование виртуальных сред для разработки Python не является одним. Для каждого
нового проекта Python следует использовать выделенную виртуальную среду.
Исторически разработчики Python использовали virtualenv или pyenv для настройки
виртуальных сред. Но в 2017 известных разработчиков Python KennethReitz Выпущено Pipenv
который теперь официально Рекомендуемый инструмент упаковки питона.
Pipenv похож на npm и yarn из экосистемы узлов: он создает файл канала, содержащий
зависимости программного обеспечения и Pipfile. Блокировка для обеспечения
детерминированных построений. “Детерминизм” означает, что каждый раз, когда вы
загружаете программное обеспечение в новой виртуальной среде, у вас будет точно такой
же конфигурации. Себастьян Маккензи, создатель Yarn, который впервые представил эту
концепцию для упаковки JavaScript, имеет краткое сообщение в блоге, объясняющее, что
такое детерминизм и почему это имеет значение.
Конечным результатом является то, что мы создадим новую виртуальную среду с pipenv
для каждого нового проекта Django.
Для установки Pipenv мы можем использовать pip , который автоматически установился
для нас вместе с Python 3.
Группа в ВК "Django_Python"
16
Chapter 1: Initial Setup
Command Line
$ pip
install pipenv
Установка Django
Чтобы увидеть Pipenv в действии, давайте создадим новый каталог и установим Django.
Сначала перейдите на рабочий стол, создайте новый каталог django и введите его с cd.
Command Line
$ cd ~/Desktop
$ mkdir django
$ cd django
Теперь используйте Pip env для установки Django.
Command Line
$ pipenv install django
Если вы посмотрите в наш каталог, есть два новых файла: Popfile и Pipe-file.lock. У нас есть
информация, необходимая для новой виртуальной среды, но мы ее еще не активировали.
Давайте сделаем это с помощью оболочки pip env shell.
Command Line
$ pipenv shell
Если вы находитесь на Mac, вы должны увидеть круглые скобки в командной строке с
активированной средой. Он примет формат имени каталога и случайных символов. На моем
компьютере я вижу нижеследующее, но вы увидите что-то немного другое: он начнется с
django- но заканчится случайной серией символов.
Группа в ВК "Django_Python"
17
Chapter 1: Initial Setup
Обратите внимание, что из-за открытой ошибки пользователи Windows не будут видеть
визуальную обратную связь виртуальной среды в это время. Но если вы сможете запустить
Django-admin startproject в следующем разделе, то вы узнаете, что в вашей виртуальной
среде установлен Django.
Command Line
(django-JmZ NTQw) $
Это означает, что все работает! Создайте новый проект Django с именем test с помощью
следующей команды. Не забудьте поставить точку в конце через пробел.
Command Line
(django-JmZ NTQw) $ django-admin startproject test_project .
Стоит остановиться здесь, чтобы объяснить, почему вы должны добавить точку через
пробел к команде. Если вы просто запустите django-admin startproject test_project, то по
умолчанию Django создаст эту структуру каталогов:
└── test_project
├── manage.py
└── test_project
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
Посмотрите, как он создает новый каталог test_project, а затем в нем manage.py файл и
каталог test_project? Это кажется мне излишним, так как мы уже создали и перешли в папку
django на нашем рабочем столе. Запустив django-admin startproject test_project . с точкой в
конце-который говорит, установите в текущем каталоге Результат вместо этого будет:
Группа в ВК "Django_Python"
18
Chapter 1: Initial Setup
├── manage.py
└── test_project
├── __init__.py
├── settings.py
├── urls.py
└── wsgi.py
Вывод заключается в том, что на самом деле не имеет большого значения, ставите ли вы
точку или нет в конце команды, но я предпочитаю ставить ее, и именно так мы сделаем в
этой книге.
Теперь давайте проверим, что все работает, запустив локальный веб-сервер Django.
Command Line
(django-JmZ NTQw) $ python manage.py runserver
Если вы перейдете в http://127.0.0.1:8000/ вы должны увидеть следующее изображение:
Группа в ВК "Django_Python"
19
Chapter 1: Initial Setup
Страница приветствия Django
Чтобы остановить наш локальный сервер, введите Control-c. Затем выйдите из нашей
виртуальной среды с помощью команды exit.
Command Line
(django-JmZ NTQw) $ exit
Мы всегда можем снова активировать виртуальную среду с помощью pipenv shell в любое
время.
Мы получим много практики с виртуальными средами в этой книге, так что не волнуйтесь,
если это
Группа в ВК "Django_Python"
20
Chapter 1: Initial Setup
немного сбивает вас с толку сейчас. Основной шаблон заключается в установке новых
пакетов с pipenv, активируйте их с помощью pipenv shell, а затем выйти, когда закончите
exit.
Стоит отметить, что одновременно на вкладке командной строки может быть активна
только одна виртуальная среда. В следующих главах мы будем создавать совершенно новую
виртуальную среду для каждого нового проекта. Так что либо не забудьте выйти из текущей
среды, либо откройте новую вкладку для новых проектов.
Установка Git
Git является неотъемлемой частью современной разработки программного обеспечения.
Это система контроля версий, которая может рассматриваться как чрезвычайно мощная
версия отслеживания изменений в Microsoft Word или Google Docs. С помощью git вы
можете сотрудничать с другими разработчиками, отслеживать всю вашу работу с помощью
фиксаций и возвращаться к любой предыдущей версии вашего кода, даже если вы случайно
удалили что-то важное!
На Mac, поскольку Homebrew уже установлен, мы можем просто ввести brew install git в
командной строке:
Command Line
$ brew install git
В Windows вы должны скачать Git из Git for Windows. Нажмите кнопку «Загрузить» и
следуйте инструкциям по установке. Нажмите «Далее» на всех шагах, кроме пятого,
“Adjusting your PATH environment.” Вместо этого выберите нижнюю опцию: “Use Git and
optional Unix tools from the Windows Command Prompt.”
После установки нам нужно выполнить одноразовую настройку системы, чтобы настроить
ее, объявив имя и адрес электронной почты, которые вы хотите связать со всеми вашими
обязательствами Git (подробнее об этом в ближайшее время).
В консоли командной строки введите следующие две строки. Не забудьте обновить их имя и
адрес электронной почты.
Группа в ВК "Django_Python"
21
Chapter 1: Initial Setup
Command Line
$ git config --global user.name "Your Name"
$ git config --global user.email "yourname@email.com"
Вы всегда можете изменить эти настройки, если пожелаете, введя те же команды с новым
именем или адресом электронной почты.
Текстовой редактор
Последний шаг это ваш текстовый редактор. В то время как командная строка, где мы
выполняем команды для наших программ по сути текстовый редактор. Компьютеру все
равно, какой текстовый редактор вы используете конечный результат просто код, но
хороший текстовый редактор может предоставить полезные советы и поймать опечатки для
вас.
Опытные разработчики часто предпочитают использовать либо Vim, либо Emacs, оба
десятилетних текстовых редактора с лояльными последователями. Однако каждый из них
имеет крутую кривую обучения и требует запоминания множества различных комбинаций
клавиш. Я не рекомендую их новичкам.
Современные текстовые редакторы сочетают в себе те же мощные функции с
привлекательным визуальным интерфейсом. Мой текущий фаворит это Visual Studio Code,
который является бесплатным, простым в установке и пользуется широкой популярностью.
Если вы еще не используете текстовый редактор, загрузите и установите Visual Studio Code.
Вывод
УФ! Никто на самом деле не любит настраивать локальную среду разработки, но, к счастью,
это одноразовая боль. Теперь мы научились работать с виртуальными средами и
установили последнюю версию Python и git. Все готово для вашего первого приложения на
Django.
Группа в ВК "Django_Python"
Глава 2 : Hello World приложение
В этой главе мы будем строить проект Django, который просто говорит: “Привет, мир” на
главной странице. Это традиционный способ начать новый язык программирования или
фреймворк. Мы также впервые будем работать с git и развертывать наш код в Bitbucket.
Начальная настройка
Для начала перейдите в новый каталог на компьютере. Например, мы можем создать папку
helloworld на рабочем столе с помощью следующих команд.
Command Line
$ cd ~/Desktop
$ mkdir helloworld
$ cd helloworld
Убедитесь, что вы еще не находитесь в существующей виртуальной среде и у вас
отображается текст в скобках () перед знаком доллара $. Чтобы выйти из него, введите exit и
нажмите ENTER. Скобки должны исчезнуть, что означает, что виртуальная среда больше не
активна. Мы будем использовать pipenv для создания новой виртуальной среды, установить
Django и затем активировать его.
Группа в ВК "Django_Python"
Chapter 2: Hello World app
23
Command Line
$ pipenv install django
$ pipenv shell
Если Вы находитесь на Mac, вы должны увидеть скобки в начале командной строки в форме
(helloworld-XXX) где XXX представляет случайные символы. На моем компьютере я вижу
(helloworld-���ivvZC). Я покажу (helloworld) здесь в тексте, но вы увидите что-то немного
другое на своем компьютере. Если Вы находитесь в Windows, Вы не увидите визуальную подсказку в это
время.
Создайте новый проект Django под названием helloworld_project включая пробел с точкой в конце
команды, так что бы он установился в нашем текущем каталоге.
Command Line
(helloworld) $ django-admin startproject helloworld_project .
Если сейчас вы используете команду tree вы можете увидеть, что наша структура проекта
Django теперь выглядит так. (Примечание: если tree у вас не работает установите его с
Homebrew:: brew install tree.)
Command Line
(helloworld) $ tree
.
├── helloworld_project
│
├── __init__.py
│
├── settings.py
│
├── urls.py
│
└── wsgi.py
└── manage.py
Группа в ВК "Django_Python"
Chapter 2: Hello World app
directory,
24
files
Файл settings.py управляет настройками нашего проекта, urls.py сообщает Django какие
страницы для сборки выдать в ответ на запрос браузера или url, и wsgi.py который
обозначает интерфейс шлюза веб-сервера и помогает Django обслуживать наши возможные
веб-страницы. Последний файл manage.py используется для выполнения различных команд
Django, таких как запуск локального веб-сервера или создание нового приложения.
Django поставляется со встроенным веб-сервером для локальных целей разработки. Мы
можем запустить его с помощью команды runerver.
Command Line
(helloworld) $ python manage.py runserver
Если вы посетите http://127.0.0.1:8000/ вы должны увидеть следующее изображение:
Группа в ВК "Django_Python"
25
Chapter 2: Hello World app
Django страница приветствия
Создание приложения
Django использует концепцию проектов и приложений, чтобы сохранить код чистым и
читаемым. Один проект Django содержит одно или несколько приложений, которые все
вместе обеспечивают работу всего веб-приложения. Вот почему команда для нового
проекта Django-startproject! Например, на реальном сайте электронной коммерции Django
может быть одно приложение для проверки подлинности пользователя, другое
приложение для платежей и третье приложение для получения сведений о списке
элементов. Каждое фокусируется на изолированной части функциональности.
Группа в ВК "Django_Python"
Chapter 2: Hello World app
26
Нам нужно создать наше первое приложение, которое мы назовем pages. Из командной
строки закройте сервер с помощью Control+c. Затем используйте команду startup.
Command Line
(helloworld) $ python manage.py startapp pages
Если снова заглянуть в каталог дерева команд вы увидите, что Джанго создал страницы со
следующими файлами:
Command Line
├── pages
│
├── __init__.py
│
├── admin.py
│
├── apps.py
│
├── migrations
│
│
│
├── models.py
│
├── tests.py
│
└── views.py
└── __init__.py
Давайте рассмотрим, что делает каждый новый файл приложения pages:
• admin.py файл конфигурации для встроенного приложения администратора Django
• apps.py является конфигурационным файлом для самого приложения
• migrations/ отслеживает любые изменения в файле models.py чтобы синхронизировать
нашу базу данных с models.py
• models.py тут мы определяем наши модели базы данных, которые Django
автоматически переводит в таблицы базы данных
• tests.py предназначен для тестирования приложений
Группа в ВК "Django_Python"
Chapter 2: Hello World app
27
• views.py тут мы обрабатываем логику запроса / ответа для нашего вебприложения
Несмотря на то, что Наше новое приложение существует в проекте Django, Django не “знает”
об этом, пока мы явно не добавим его. В текстовом редакторе откройте settings.py файл и
прокрутите вниз до INSTALLED_APPS, где вы увидите шесть уже встроенных приложений
Django. Добавьте наше новое приложение внизу:
Code
# helloworld_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pages', # new
]
Views и URLConfs
В Django, Views определяет, какой контент выводится на данной странице, URLConfs
определяет, где этот контент будет.
Когда пользователь запрашивает определенную страницу, например домашнюю страницу,
URLConf использует регулярное выражение для сопоставления этого запроса с
соответствующей Views функцией , которая затем возвращает правильные данные.
Другими словами, наша функция из Views выведет текст «Hello, World», в то время как наш
URL будет гарантировать, что когда пользователь посещает главную страницу, он будет
перенаправляется на правильную функцию Views.
Начнем с обновления файла views.py в нашем pages приложении выглядит это следующим
образом:
Группа в ВК "Django_Python"
Chapter 2: Hello World app
28
Code
# pages/views.py
from django.http import HttpResponse
def homePageView(request):
return HttpResponse('Hello, World!')
В принципе, мы указываем, что всякий раз, когда вызывается функция homePageView
вернется текст “Hello, World!” если более конкретно то мы импортировали встроенный
HttpResponse метод, чтобы мы могли вернуть ответ объекта пользователю. Для этого мы
создали функцию с именем homePageView которая принимает запрос объекта и возвращает
ответ со строкой Hello, World!.
Теперь нам нужно настроить наш URL. В приложении pages создайте новый urls.py файл.
Command Line
(helloworld) $ touch pages/urls.py
Затем обновите его с помощью следующего кода:
Группа в ВК "Django_Python"
Chapter 2: Hello World app
29
Code
# pages/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.homePageView, name='home')
]
В верхней строке мы импортируем path из Django, чтобы использовать наш шаблон url, и на
следующей строке мы импортируем наш файл views. Использованный пробел с точкой
from . import views означает ссылку на текущий каталог, который является нашим
приложением pages, содержащим как views.py, так и urls.py.
Наш шаблон URL состоит из трех частей:
• регулярное выражение Python для пустой строки ''
• указывает функцию homePageView из файла views
• добавляет не обязательное url имя'home'
Другими словами, если пользователь запрашивает домашнюю страницу, представленную
пустой строкой " , то используется функция файла views с именем homePageView.
Мы уже почти закончили. Последний шаг это настройка на уровне проекта файла urls.py.
Помните, что обычно в одном проекте Django есть несколько приложений, поэтому
каждому из них нужен свой собственный маршрут.
Обновите файл helloworld_project/urls.py следующим образом:
Группа в ВК "Django_Python"
Chapter 2: Hello World app
30
Code
# helloworld_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('pages.urls')),
]
Мы импортировали include во второй строке рядом с path, а затем создали новый шаблон
url-адреса для нашего приложения pages. Теперь, когда пользователь посещает главную
страницу ' ', он сначала будет перенаправлен на приложение pages, а затем на views
домашней страницы.
Это часто путает начинающих, то что нам здесь не нужно импортировать приложение pages,
но мы ссылаемся на него в нашем шаблоне url как pages.urls. Причина, по которой мы
делаем это, заключается в том, что метод django.urls.include () ожидает, что мы перейдем в
модуль или приложение в качестве первого аргумента. Поэтому без использования include
нам нужно будет импортировать наше приложение pages, но поскольку мы используем
include, мы не должны это делать на уровне проекта!
Hello, world!
У нас есть весь код, который нам сейчас нужен ! Чтобы подтвердить, что все работает так,
как и ожидалось, перезагрузите наш сервер Django:
Группа в ВК "Django_Python"
31
Chapter 2: Hello World app
Command Line
(helloworld) $ python manage.py runserver
Если вы обновите браузер для http://127.0.0.1:8000/ теперь он отображает текст “Hello,
world!”
Hello world homepage
Git
В предыдущей главе мы также установили git, который является системой контроля версий.
Давайте используем его здесь. Первый шаг - инициализировать (или добавить) git в наш
репозиторий.
Command Line
(helloworld) $ git init
Если вы введете git status то увидите список изменений с момента последней
фиксации(git commit). Поскольку это наша первая фиксация, это список всех наших
изменений до сих пор.
Группа в ВК "Django_Python"
Chapter 2: Hello World app
32
Command Line
(helloworld) $ git status
On branch master
No commits yet
Untracked files:
(use "git add <file>..." to include in what will be committed)
db.sqlite
helloworld_project/
manage.py
pages/
Pipfile
Pipfile.lock
ничего не добавлено к фиксации, но присутствуют неотслеживаемые файлы (используйте" git add " для отслеживания)
Теперь мы хотим добавить все изменения с помощью команды add-A, а затем
зафиксировать изменения вместе с сообщением, описывающим, что изменилось.
Command Line
(helloworld) $ git add -A
(helloworld) $ git commit -m 'initial commit'
Обратите внимание, что пользователи Windows могут получить сообщение об ошибке git
commit error: pathspec ‘commit’ did not match any file(s) known to которая, повидимому, связана с использованием одинарных кавычек ' ' и отличается от двойных
кавычек" ". Если вы видите эту ошибку, используйте двойные кавычки для всех сообщений
фиксации в будущем.
Группа в ВК "Django_Python"
Chapter 2: Hello World app
33
Bitbucket
Хорошей привычкой является создание удаленного хранилища кода для каждого проекта.
Таким образом, у вас есть резервная копия на случай, если что-то случится с вашим
компьютером, и, что более важно, она позволяет сотрудничать с другими разработчиками
программного обеспечения. Два самых популярных варианта Bitbucket и Github.
В этой книге мы будем использовать Bitbucket, потому что он позволяет частные
репозитории бесплатно. Github взимает за это плату. Общедоступные репозитории
доступны для всех пользователей интернета, а частные-нет. Когда вы изучаете вебразработку, лучше всего придерживаться частных репозиториев, чтобы случайно не
опубликовать важную информацию, такую как пароли в интернете.
Чтобы начать работу с Bitbucket, зарегистрируйте бесплатную учетную запись. После
подтверждения аккаунта по электронной почте вы будете перенаправлены на страницу
приветствия. Нажмите на ссылку “создать хранилище”.
Группа в ВК "Django_Python"
34
Chapter 2: Hello World app
Bitbucket страница приветствия
Затем на странице” CreateRepo “введите имя вашего репозитория:”hello-world". Затем
нажмите синюю кнопку “Create repository button”:
Группа в ВК "Django_Python"
35
Chapter 2: Hello World app
Bitbucket create repo
На следующей странице внизу, нажмите на ссылку “ I have an existing project” в
которой откроется выпадающий список:
Группа в ВК "Django_Python"
36
Chapter 2: Hello World app
Bitbucket существующий проект
Мы уже в каталоге нашего repo, пропустим Шаг 1 (Step 1). В шаге 2(Step 2) мы используем
две команды для добавления проекта в Bitbucket. Обратите внимание, что ваша команда
будет отличаться от моей, так как у вас другое имя пользователя. Пример общего формата
расположен ниже, где <USER> - Ваше имя пользователя Bitbucket.
Command Line
(helloworld) $ git remote add origin https://<USER>@bitbucket.org/<USER>/hello-w\
orld.git
После выполнения этой команды для настройки git с этим репозиторием Bitbucket мы
должны «вставить» наш код в него.
Группа в ВК "Django_Python"
37
Chapter 2: Hello World app
Command Line
(helloworld) $ git push -u origin master
Сейчас, если вы вернетесь на свою страницу Bitbucket и обновите ее, вы увидите, что код
теперь находится в онлайн! Нажмите на вкладку “Source” слева, чтобы увидеть все это.
Bitbucket обзор
После этого выйдите из виртуальной среды с помощью команды exit.
Command Line
(helloworld) $ exit
Сейчас в вашей командной строке не должно быть круглых скобок, это указывает на то, что
виртуальная среда больше не активна.
Вывод
Поздравляю! Мы охватили много фундаментальных понятий в этой главе. Мы создали
наше первое Приложение Django и узнали о структуре project/app (проект/приложение) в
Django.
Группа в ВК "Django_Python"
Chapter 2: Hello World app
38
Мы начали изучать views, urls и внутренний веб-сервер. А так же мы работали с git, чтобы
отслеживать наши изменения, и поместили наш код в частный репозиторий Bitbucket.
Перейдем к главе 3: Простое приложение, где мы создадим и развернем более сложное
приложение Django с использованием шаблонов(templates) и представлений(views) на
основе классов.
Группа в ВК "Django_Python"
Глава �: Pages приложение
В этой главе мы создадим, протестируем и развернем Приложение Pages с главной
страницей home и страницей about. Мы также узнаем о классовых views и templates Django,
которые являются строительными блоками для более сложных веб-приложений,
построенных в книге позже .
Начальная настройка
Как и в главе 2: Hello World приложение, наша первоначальная настройка включает в себя
следующие шаги:
• создание нового каталога для нашего кода
• установить Django в новой виртуальной среде
• создание нового проекта Django
• создание нового приложения pages
• обновление(настройка) settings.py
В командной строке, убедитесь, что вы не работаете в существующей виртуальной среде.
Проверьте есть ли что-нибудь в скобках перед запросом командной строки. И если есть то
просто наберите exit что бы выйти из него.
Мы снова создадим новые страницы каталога для нашего проекта на рабочем столе, но вы
можете поместить свой код в любом месте на вашем компьютере. Он просто должен быть в
своем собственном каталоге.
В новой консоли командной строки введите следующие команды:
Группа в ВК "Django_Python"
40
Chapter 3: Pages app
Command Line
$ cd ~/Desktop
$ mkdir pages
$ cd pages
$ pipenv install django
$ pipenv shell
(pages) $ django-admin startproject pages_project .
(pages) $ python manage.py startapp pages
Я использую здесь(pages) для представления виртуальной среды, но в реальности у меня
выглядит так (pages-unOYeQ�e). Имя же вашей виртуальной среды будет уникальным и
выглядеть будет примерно в таком формате (pages-XXX).
Откройте текстовый редактор и перейдите к файлу settings.py. Добавьте приложение pages
в наш проект в разделе INSTALLED_APPS:
Code
# pages_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'pages', # new
]
Запустите локальный веб-сервер с помощью команды runserver.
Группа в ВК "Django_Python"
41
Chapter 3: Pages app
Command Line
(pages) $ python manage.py runserver
И затем перейдите на http://127.0.0.1:8000/.
Django страница приветствия
Templates(Шаблоны)
Каждый веб-фреймворк нуждается в удобном способе создания HTML файлов. В Django,
подход заключается в использовании шаблонов(templates), так что бы отдельные HTML
файлы могли обслуживаться в view веб-страницы, указанным URL.
Группа в ВК "Django_Python"
42
Chapter 3: Pages app
Стоит повторить эту модель, так как вы увидите ее снова и снова в Django разработке :
Templates, Views и URLs. Порядок, в котором вы их создаете, не имеет большого значения,
поскольку все три необходимы и работают в тесном сотрудничестве. URLs управляют
начальным маршрутом, точкой входа на страницу, например /about,
views содержат
логику, а шаблон имеет HTML. Для веб-страниц, использующих модели базы данных, views
делает большую часть работы по определению какие данные доступны в шаблоне.
И так: Templates, Views, URLs. Эта модель будет справедлива для каждой веб-страницы
Django которую вы делаете. Однако потребуется некоторая практика, прежде чем вы
усвоите это.
Ок, двигаемся дальше. Вопрос о том, где разместить каталог шаблонов(templates), может
смутить новичков. По умолчанию Django ищет шаблоны в каждом приложении. Наше
pages приложение будет ожидать шаблон home.html который расположен в следующей
директории:
└── pages
├── templates
├── pages
├── home.html
Это означает, что нам нужно будет создать новый каталог шаблонов(templates), новый
каталог с именем приложения, pages, и наконец, сам наш шаблон home.html
Общий вопрос: почему эта повторяющаяся структура? Короткий ответ заключается в том,
что загрузчик шаблонов Django хочет быть действительно уверен, что он найдет
правильный шаблон, и именно так он запрограммирован на их поиск.
К счастью, есть еще один часто используемый подход построения шаблонов Djangoпроекта. Вместо этого необходимо создать единый каталог шаблонов на уровне проекта,
доступный для всех приложений. Это тот подход, который мы и будем использовать.
Группа в ВК "Django_Python"
43
Chapter 3: Pages app
Сделав небольшую настройку в файле settings.py, мы можем указать Django также искать в
папке на уровне проекта для шаблонов.
Сначала остановите наш сервер с помощью Control-c. Затем создайте папку на уровне
проекта с именем templates и HTML файл с именем home.html.
Command Line
(pages) $ mkdir templates
(pages) $ touch templates/home.html
Далее нам нужно обновить settings.py и указать Django, чтобы он искал шаблоны на уровне
проекта. Для этого изменим строку 'DIRS' под TEMPLATES.
Code
# pages_project/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
Затем мы можем добавить простой заголовок к нашему home.html файлу.
Группа в ВК "Django_Python"
44
Chapter 3: Pages app
Code
<!-- templates/home.html -->
<h1>Homepage.</h1>
Ок, наш шаблон готов! Следующий шаг это настройка url и views.
Class-Based Views
Ранние версии Django поставлялись только с функциональными views, но вскоре
разработчики обнаружили что снова и снова повторяли одни и те же действия. Напишите
view со списком всех объектов в модели. Напишите view, в котором отображается только
один подробный элемент модели и так далее.
Основанные на функциях view, были представлены, что бы абстрагировать эти
закономерности и оптимизировать разработку общими моделями. Однако не было
простого способа расширить или настроить их. В результате в Django появились
универсальные view на основе классов, которые упрощают использование, а также
расширяют, и охватывают распространенные варианты использования.
Классы это фундаментальная часть Python, но полное обсуждение их выходит за рамки
этой книги. Если Вы нуждаетесь в ведении или напоминании, я предлагаю рассмотреть
официальные документы Python, у которых есть превосходное учебное руководство по
классам и их использованию.
В нашем view мы будем использовать встроенный TemplateView . Обновить pages/
views.py файл.
Группа в ВК "Django_Python"
45
Chapter 3: Pages app
Code
# pages/views.py
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'home.html'
Обратите внимание, что мы капитализировали наш view, так как теперь это класс Python.
Классы, в отличие от функций, всегда должны быть капитализированы. TemplateView уже
содержит всю логику, необходимую для отображения нашего шаблона, нам просто нужно
указать имя шаблона.
URLs
Последним шагом мы обновим наш URLConfs. Вспомним из главы 2, Что нам нужно
внести изменения в двух местах. Сначала мы обновляем на уровене проекта urls.py файл,
чтобы указать на наше pages приложение, а затем в urls.py файле pages приложения мы
сопоставим с маршрутами views .
Давайте начнем с уровня проекта urls.py файл.
Группа в ВК "Django_Python"
46
Chapter 3: Pages app
Code
# pages_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('pages.urls')),
]
Давайте рассмотрим код на этом этапе. Мы добавили include во второй строке, чтобы
указать существующий URL-адрес приложения pages.
Далее создайте на уровне приложения urls.py файл.
Command Line
(pages) $ touch pages/urls.py
И добавьте следующий код.
Code
# pages/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
]
Группа в ВК "Django_Python"
47
Chapter 3: Pages app
Этот шаблон почти идентичен тому, что мы сделали в главе 2 с одним существенным
отличием. При использовании Views на основе класса мы всегда добавляем as_view() в
конце имени view.
Мы закончили! Если сейчас вы запустите сервер командой python manage.py runserver и
перейдете к http://127.0.0.1:8000/ вы увидете нашу новую домашнюю страницу.
Домашняя страница
Добавить About страницу
Процесс добавления страницы очень похож на то, что мы только что сделали. Мы создадим
новый файл шаблона, новый view и новый url.
Закройте сервер с помощью Control-c и создайте новый шаблон с именем about.html.
Command Line
(pages) $ touch templates/about.html
Затем введите в него короткий HTML заголовок.
Группа в ВК "Django_Python"
48
Chapter 3: Pages app
Code
<!-- templates/about.html -->
<h1>About page.</h1>
Создайте новый view для страницы.(подразумевается создать новый класс или функцию в данном случае
классAboutPageView)
Code
# pages/views.py
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'home.html'
class AboutPageView(TemplateView):
template_name = 'about.html'
А затем подключите его к url-адресу about/.
Группа в ВК "Django_Python"
49
Chapter 3: Pages app
Code
# pages/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
path('about/', views.AboutPageView.as_view(), name='about'),
]
Запустите веб сервер командой python manage.py runserver.
Перейдите к http://127.0.0.1:8000/about и вы увидите нашу новую страницу
“About page”.
About page
Расширение Шаблонов
Реальная сила шаблонов заключается в их способности расширяться. Если вы сейчас
вспомните то у большинства веб сайтов, которые повторяются на каждой странице
(заголовок, нижний колонтитул, и т.д.). И было бы неплохо, если бы у нас, как
разработчиков, могло быть одно каноническое место для нашего кода заголовка, который
бы наследовался всеми другими шаблонами.
Группа в ВК "Django_Python"
50
Chapter 3: Pages app
И это возможно! Давайте создадим файл base.html содержащий заголовок с ссылками на
две наши страницы. Сначала Control-c а затем введите следующую команду.
Command Line
(pages) $ touch templates/base.html
Django имеет минимальный язык шаблонов для добавления ссылок и базовой логики в
наши шаблоны. Вы можете увидеть полный список встроенных шаблонов здесь в
официальной документации. Теги шаблонов имеют вот такую форму{% что-то %} где “чтото” - это сам тег шаблона. Вы даже можете создать свои собственные теги шаблонов, хотя
мы не будем делать этого в этой книге.
Чтобы добавить URL-ссылки в наш проект, мы можем использовать встроенный тег
шаблона url, который принимает имя шаблона URL в качестве аргумента. Помните, как мы
добавили необязательные имена URL в наши URL-маршруты? Вот для чего. Тег url
автоматически использует эти имена для того чтобы создать соединения для нас.
URL-Адрес нашей домашней страницы называется home, поэтому для настройки ссылки на
нее мы будем использовать следующее: {% url 'home' %}.
Code
<!-- templates/base.html -->
<header>
<a href="{% url 'home' %}">Home</a> | <a href="{% url 'about' %}">About</a>
</header>
{% block content %}
{% endblock %}
В нижней части мы добавили тег блока content. Блоки могут быть перезаписаны дочерними
шаблонами с помощью наследования.
Группа в ВК "Django_Python"
51
Chapter 3: Pages app
Давайте обновим наш home.html и about.html для расширения base.html шаблона. Это
означает, что мы можем повторно использовать код из одного шаблона в другой шаблон.
Язык шаблонов Django поставляется с методом extends, который мы можем использовать
для этого.
Code
<!-- templates/home.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Homepage.</h1>
{% endblock %}
Code
<!-- templates/about.html -->
{% extends 'base.html' %}
{% block content %}
<h1>About page.</h1>
{% endblock %}
Запустите сервер командой python manage.py runserver и снова откройте наш сайт
http://127.0.0.1:8000/ и http://127.0.0.1:8000/about вы увидите, что заголовок
волшебным образом включен в обоих местах.
Правда приятно?
Группа в ВК "Django_Python"
52
Chapter 3: Pages app
Домашняя страница с заголовком
About страница с заголовком
С шаблонами мы можем сделать гораздо больше, на практике мы обычно создаем base.html
файл, а затем добавляем дополнительные шаблоны поверх него в надежном проекте
Django. Мы сделаем это позже в книге.
Tests
Наконец мы подошли к тестам. Даже в этом базовом приложении важно добавлять тесты и
иметь привычку всегда добавлять их в наши проекты Django. По словам Джейкоба КапланМосса, одиного из создателей Джанго, “код без тестов нарушен полностью.”
Написание тестов важно, поскольку оно автоматизирует процесс подтверждения того, что
код работает должным образом. В таком приложении, как это, мы можем вручную
посмотреть и увидеть, что страница homepage и страница about page существуют и
содержат предполагаемое содержание. Но как только Django
Группа в ВК "Django_Python"
53
Chapter 3: Pages app
проект начинает расти в размерах и в нем могут быть сотни, если не тысячи отдельных вебстраниц и идея вручную посетить каждую страницу становится невозможной. Далее,
каждый раз, когда мы вносим изменения в код и добавляем новые функции, обновляем
существующие, или удаляем неиспользуемые области сайта мы хотим быть уверены, что
случайно не сломали какую-то другую часть сайта. Автоматизированные тесты позволяют
нам написать один раз, как мы ожидаем будет работать определенная часть нашего
проекта, а затем пусть компьютер делает проверку за нас.
К счастью, Django поставляется с надежными, встроенными инструментами тестирования
для написания и запуска тестов.
Если вы посмотрите на наши страницы приложения, Django уже снабжен, tests.py файлом,
который мы можем использовать. Откройте его и добавьте следующий код:
Code
# pages/tests.py
from django.test import SimpleTestCase
class SimpleTests(SimpleTestCase):
def test_home_page_status_code(self):
response = self.client.get('/')
self.assertEqual(response.status_code,
)
def test_about_page_status_code(self):
response = self.client.get('/about/')
self.assertEqual(response.status_code,
)
Мы используем здесь SimpleTestCase поскольку мы не используем базу данных. Если бы
мы использовали базу данных, мы бы использовали TestCase. Затем мы выполняем
проверку состояния кода
Группа в ВК "Django_Python"
54
Chapter 3: Pages app
для 200 страниц, это стандартный ответ для успешного запроса HTTP. И это
причудливый способ сказать, что гарантированно данная веб-страница реально
существует, но ничего не говорит о содержании указанной страницы.
Для запуска тестов закройте server Control-c и введите python manage.py test в командной
строке:
Command Line
(pages) $ python manage.py test
Creating test database for alias 'default'...
..
---------------------------------------------------------------------Ran
tests in
.
s
OK
Destroying test database for alias 'default'...
Получилось! В будущем мы сделаем гораздо больше с тестированием, особенно когда
начнем работать с базами данных. На данный момент важно видеть, как легко добавлять
тесты каждый раз, когда мы добавляем новую функциональность в наш Django проект.
Git и Bitbucket
Пришло время отслеживать наши изменения с git и выводить в Bitbucket. Начнем с
инициализации каталога.
Группа в ВК "Django_Python"
55
Chapter 3: Pages app
Command Line
(pages) $ git init
Используйте git status, чтобы увидеть все наши изменения кода, а затем git add -A, чтобы
добавить их все. Наконец, мы добавим наше первое сообщение о фиксации.
Command Line
(pages) $ git status
(pages) $ git add -A
(pages) $ git commit -m 'initial commit'
На Bitbucket создайте новый репозиторий, который мы назовем pages-app.
Bitbucket создание страницы
На следующей странице нажмите на ссылку с низу “I have an existing project”.
Скопируйте две команды для подключения, а затем нажмите repository to Bitbucket.
Группа в ВК "Django_Python"
56
Chapter 3: Pages app
Bitbucket Existing Project(существующий проект)
Он должен выглядеть следующим образом, замените wsvincent вашим именем
пользователя Bitbucket:
Command Line
(pages) $ git remote add origin git@bitbucket.org:wsvincent/pages-app.git
(pages) $ git push -u origin master
Local vs Production
До этого момента мы использовали собственный внутренний веб-сервер Django для
работы нашего приложения Pages на нашем локальном компьютере. Но Вы не можете
поделиться адресом localhost с кем-то еще. Чтобы сделать наш сайт доступным в интернете,
где его может видеть каждый, нам нужно развернуть наш код на внешнем сервере, что бы
каждый мог просматривать наш сайт.
Группа в ВК "Django_Python"
57
Chapter 3: Pages app
Это называется вводом кода в производство (production). Локальный код работает только
на нашем компьютере; производственный код на внешнем сервере.
Есть много доступных поставщиков серверов, но мы будем использовать Heroku, потому
что он бесплатен для небольших проектов, широко используется и имеет относительно
простой процесс развертывания.
Heroku
Вы можете зарегистрировать бесплатный аккаунт на сайте Heroku и после того, как вы
подтвердите свою электронную почту Heroku перенаправит вас в раздел панели
инструментов сайта.
Heroku панель инструментов
Теперь нам необходимо установить Heroku’s Command Line Interface (CLI), так что мы
можем развернуть его из командной строки. Нам нужно установить Heroku глобально,
чтобы он был доступен на всем нашем компьютере, поэтому откройте новую вкладку
командной строки: Command + t на Mac, Control+ t на Windows. Если бы мы установили
Heroku в нашей виртуальной среде, она была бы доступна только там.
В новой вкладке на Mac используйте Homebrew для установки Heroku:
Группа в ВК "Django_Python"
58
Chapter 3: Pages app
Command Line
$ brew install heroku
Для правильной установки 32-разрядной или 64-разрядной версии Windows см. страницу
Heroku CLI.
После завершения установки вы можете закрыть нашу новую вкладку командной строки и
вернуться на начальную вкладку с активной виртуальной средой pages.
Введите команду heroku login и использованную электронную почту и пароль которые вы
указали при регистрации на Heroku.
Command Line
(pages) $ heroku login
Enter your Heroku credentials:
Email: will@wsvincent.com
Password: *********************************
Logged in as will@wsvincent.com
Дополнительный файл
Нам необходимо внести следующие четыре изменения в наш проект Pages, чтобы он был
готов к развертыванию онлайн на Heroku:
• обновить Pipfile.lock
• создать новый файл профиля (Procfile file)
• установить gunicorn как наш веб-сервер
• внести однострочное изменение в settings.py файл
В существующем Pipfile укажите версию Python которую мы используем, то есть �.�.
Добавьте эти две строки в конец файла.
Группа в ВК "Django_Python"
59
Chapter 3: Pages app
Code
# Pipfile
[requires]
python_version = " . "
Затем запустите pipenv lock для создания соответствующего файла
Pipfile.lock.
Command Line
(pages) $ pipenv lock
Фактически Heroku ищет в нашем Pipfile.lock информацию о нашей виртуальной
среде, поэтому мы здесь добавляем настройки языка.
Затем создайте Procfile который является специфическим для Heroku.
Command Line
(pages) $ touch Procfile
Откройте файл Procfile в текстовом редакторе и добавьте
следующее:
Code
web: gunicorn pages_project.wsgi --log-file -
Это указывает на то что используется наш существующий файл pages_project.wsgi но с
gunicorn, который является веб сервером и подходит для производства (production),
вместо Django сервера который используется только для локальной разработки.
Группа в ВК "Django_Python"
60
Chapter 3: Pages app
Command Line
(pages) $ pipenv install gunicorn
Последний шаг это однострочное изменение в settings.py. Прокрутите вниз до раздела
ALLOWED_HOSTS и добавьте '*', чтобы он выглядело как в примере ниже:
Code
# pages_project/settings.py
ALLOWED_HOSTS = ['*']
Параметр ALLOWED_HOSTS представляет имена хостов/доменов, которые может
обслуживать наш Django сайт. Это мера безопасности, предотвращающая атаки на HTTP
Host header, которые возможны даже при многих, казалось бы, безопасных конфигурациях
веб-сервера. Однако мы использовали подстановочный знак звездочку *, который означает,
что все домены приемлемы, для простоты. На сайте Django уже на уровне
производства(production) вы должны явно указать, какие домены разрешены.
Используйте git status, чтобы проверить наши изменения, добавить новые файлы, а затем
зафиксировать их:
Command Line
(pages) $ git status
(pages) $ git add -A
(pages) $ git commit -m "New updates for Heroku deployment"
И наконец отправим на Bitbucket чтобы у нас была онлайн резервная копия наших изменений кода.
Группа в ВК "Django_Python"
61
Chapter 3: Pages app
Command Line
(pages) $ git push -u origin master
Deploy (Развертывание)
Заключительный шаг фактически разворачивает на Heroku. Если вы в прошлом
настраивали сервер самостоятельно, то вы будете поражены тем, насколько простой
процесс с провайдером сервис платформы таким как Heroku.
Наш процесс будет следующим:
• Создадим новое приложение на Heroku и отправляем на него наш код.
• Добавим удаленный git “hook” для Heroku
• Настроим приложение, чтобы оно игнорировало статические файлы, которые
мы рассмотрим в последующих главах.
• Запустим сервер Heroku, чтобы приложение заработало.
• Посетим приложение на Heroku с предоставленным URL
Мы можем сделать первый шаг, создав новое приложение Heroku, из командной строки
heroku create. Heroku создаст случайное имя для нашего приложения, в моем случае это
cryptic-oasis-�����. у вас имя будет другим.
Command Line
(pages) $ heroku create
Creating app... done,
https://cryptic-oasiss-
cryptic-oasis.herokuapp.com/ | https://git.heroku.com/cryptic-oasi\
.git
Теперь нам нужно добавить “hook” для Heroku в git. Это означает, что git сохранит обе
наши настройки для отправки кода на Bitbucket и Heroku. Мое Приложение Heroku
называется cryptic-oasis-����� поэтому моя команда выглядит следующим образом.
Группа в ВК "Django_Python"
62
Chapter 3: Pages app
Command Line
(pages) $ heroku git:remote -a cryptic-oasis-
Вы должны заменить cryptic-oasis-40349 на имя приложения которое предоставил Heroku.
На данный момент нам нужно сделать только одину настройку конфигурации Heroku,
которая должна указать Heroku игнорировать статические файлы, такие как CSS и
JavaScript, которые Django по умолчанию пытается оптимизировать для нас. Мы
рассмотрим это в последующих главах, так что пока просто выполните следующую
команду.
Command Line
(pages) $ heroku config:set DISABLE_COLLECTSTATIC=
Теперь мы можем отправить наш код на Heroku. Потому что ранее мы установили наш
“hook” и он уйдет на Heroku.
Command Line
(pages) $ git push heroku master
Если мы просто наберем git push origin master, то код будет перенесен в Bitbucket, а не в
Heroku. Добавив heroku к команде пошлет код на Heroku. Это немного сбивает с толку
первое время.
Наконец, нам необходимо сделать ваше приложение Heroku рабочим. Поскольку веб-сайты
растут в трафике, им нужны дополнительные услуги Heroku, но для нашего основного
примера мы можем использовать самый низкий уровень, web=�, который также является
бесплатным!
Введите следующую команду.
Группа в ВК "Django_Python"
63
Chapter 3: Pages app
Command Line
(pages) $ heroku ps:scale web=
Мы закончили! Последний шаг, это подтвердить что наше приложение работает в
интернете. Если вы используете команду heroku open веб-браузер откроет новую вкладку с
URL вашего приложения:
Command Line
(pages) $ heroku open
У меня это https://cryptic-oasis-40349.herokuapp.com/about/. Вы сможете увидеть
страницу homepage и страницу about page .
Страница Homepage на Heroku
Страница About page на Heroku
Группа в ВК "Django_Python"
64
Chapter 3: Pages app
Вывод
Поздравляем с созданием и развертыванием второго проекта Django! На этот раз мы
использовали шаблоны, классовые vews, более полно исследовали URLConfs, добавили
базовые тесты и использовали Heroku. Далее мы перейдем к нашему первому проекту с
базой данных и посмотрим, где действительно Django блистает.
Группа в ВК "Django_Python"
Глава �: Message Board app (Приложение доска объявлений)
В этой главе мы будем использовать базу данных в первый раз, чтобы построить базовое
приложение доска объявлений, где пользователи могут отправлять и читать короткие
сообщения. Мы рассмотрим мощный встроенный интерфейс администратора Django,
который обеспечивает визуальный способ внесения изменений в наши данные. И после
добавления тестов мы будем отправлять наш код в Bitbucket и развернем приложение на
Heroku.
Django предоставляет встроенную поддержку для нескольких типов баз данных. Имея
всего несколько строк в нашем файле settings.py, он может поддерживать PostgreSQL,
MySQL, Oracle или SQLite. Но самым простым на сегодняшний день-является SQLite,
потому что он работает с одним файлом и не требует сложной установки. В отличие от
других, опции которых требуют, чтобы процессы работали в фоновом режиме и могут быть
довольно сложными для настройки. Django использует SQLite по умолчанию и это
идеальный выбор для небольших проектов.
Начальная настройка
Так как мы уже создали несколько проектов Django в этой книге, мы можем быстро
выполнить наши команды, чтобы начать новый проект. Нам необходимо выполнить
следующее:
• создать новый каталог для нашего кода на рабочем столе под названием mb
• установить Django в новой виртуальной среде
• создать новый проект с именем mb_project
• создать новое приложение posts
• обновить settings.py
Группа в ВК "Django_Python"
Chapter 4: Message Board app
66
В новой консоли командной строки введите следующие команды. Обратите внимание, что
я использую здесь (mb) для представления имени виртуальной среды, хотя на самом деле
(mb-XXX), где XXX случайные символы.
Command Line
$ cd ~/Desktop
$ mkdir mb
$ cd mb
$ pipenv install django
$ pipenv shell
(mb) $ django-admin startproject mb_project .
(mb) $ python manage.py startapp posts
Укажите Django о новом приложении posts, добавив его в нижнюю часть раздела
INSTALLED_APPS вашего settings.py файла открыв его в текстовом редакторе.
Code
# mb_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'posts', # new
]
Затем выполните команду migrate, чтобы создать исходную базу данных на основе настроек
Django по умолчанию.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
67
Command Line
(mb) $ python manage.py migrate
Если вы посмотрите в наш каталог с помощью команды ls, вы увидите, что у нас появился
файл db.sqlite� представляющий нашу базу данных SQLite.
Command Line
(mb) $ ls
db.sqlite
mb_project manage.py
Отступление: Технически файл db.sqlite� создается при первом запуске migrate или
runserver. Использование runserver формирует базу данных, используя настройки Django
по умолчанию, однако migrate будет синхронизировать базу данных с текущим состоянием
любых моделей баз данных, находящихся в проекте и внесенных в INSTALLED_APPS.
Другими словами, чтобы убедиться, что база данных отражает текущее состояние проекта,
необходимо использовать migrate (а также makemigrations) при каждом обновлении
модели. Более подробно об этом чуть позже.
Чтобы убедиться, что все работает правильно, запустите наш локальный сервер.
Command Line
(mb) $ python manage.py runserver
И перейдите к http://127.0.0.1:8000/ что бы увидеть хорошо знакомую страницу, Django
установлен правильно.
Группа в ВК "Django_Python"
68
Chapter 4: Message Board app
Django welcome page
Создание модели базы данных
Наша первая задача создать модель базы данных, где мы можем хранить и отображать
сообщения от наших пользователей. Для нас Django превратит эту модель в таблицу базы
данных. В реальных проектах Django часто бывает так, что будет много сложных
взаимосвязанных моделей баз данных, но в нашем простом приложении для доски
объявлений нам нужна только одна.
Я не буду рассматривать конструкцию базы данных в этой книге, но я написал краткое
руководство, которое вы можете найти здесь, если это новое для вас.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
69
Откройте файл posts/models.py и посмотрите на код по умолчанию, который
предоставляет Django:
Code
# posts/models.py
from django.db import models
# Create your models here
Django импортирует модуль models, чтобы помочь нам построить новые модели баз
данных, которые будут “моделировать” характеристики данных в нашей базе данных. Мы
хотим создать модель для хранения текстового содержимого сообщений в доске
объявлений, которую мы можем выполнить следующим образом:
Code
# posts/models.py
from django.db import models
class Post(models.Model):
text = models.TextField()
Обратите внимание, что мы создали новую модель базы данных, которая имеет текстовое поле
данных. Мы также определили тип контента, который он будет содержать, TextField (). Django
предоставляет множество полей модели, поддерживающих общие типы контента, такие как
символы, даты, целые числа, электронные письма и так далее.
Активация моделей
Теперь, когда наша новая модель создана, нам нужно ее активировать. В будущем, когда мы
создаем или изменяем существующую модель необходимо обновлять Django в два этапа.
Группа в ВК "Django_Python"
70
Chapter 4: Message Board app
1. Сначала мы создаем файл миграции с помощью команды makemigrations, которая
генерирует команды SQL для предустановленных приложений в нашем параметре
INSTALLED_APPS. Файлы миграции не выполняют эти команды в файле базы
данных, а являются ссылкой на все новые изменения в наших моделях. Этот подход
означает, что у нас есть запись изменений в наших моделях .
2. Во-вторых, мы создаем фактическую базу данных с помощью migrate, которая
выполняет инструкции в нашем файле migrations.
Command Line
(mb) $ python manage.py makemigrations posts
(mb) $ python manage.py migrate posts
Обратите внимание, что вам не нужно включать имя после makemigrations или migrate.
Если вы просто запустите команды, то они будут применены ко всем доступным
изменениям. Это хорошая привычка, чтобы быть точным. Если бы у нас было два
отдельных приложения в нашем проекте, и мы обновили модели в обоих, а затем запустили
makemigrations, это создало бы файл миграции, содержащий данные об обоих изменениях.
Это усложняет отладку в будущем. Вам потребуется, чтобы каждый файл миграции был как
можно меньше и возможно отдельным. Таким образом, если вам нужно просмотреть
прошлые миграции, есть только одно изменение на миграцию, а не одно, которое
применяется к нескольким приложениям.
Django Admin
Django предоставляет нам мощный интерфейс администратора для взаимодействия с
нашей базой данных. Это поистине потрясающий функционал, который предлагают
немногие веб-фреймворки. Он имеет свои маршруты
как в Django проекте
newspaper(газета - в этой книге ниже). Разработчики хотели CMS (систему управления
контентом), чтобы журналисты могли писать и редактировать свои истории без
необходимости затрагивать "код.” Пстепенно встроенное приложение администратора
превратилось в фантастический, из коробки инструмент для управления всеми аспектами
проекта Django.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
71
Чтобы использовать Django админ, нам сначала нужно создать суперпользователя,
который может войти в систему. В консоли командной строки введите python manage.py
createsuperuser и заполните ответы на запросы для имени пользователя, электронной
почты и пароля:
Command Line
(mb) $ python manage.py createsuperuser
Username (leave blank to use 'wsv'): wsv
Email:
Password:
Password (again):
Superuser created successfully.
Примечание: При вводе пароля он не отображается в консоли командной строки по
соображениям безопасности.
Перезапустите сервер Django с помощью python manage.py runserver и в браузере перейдите
к http://127.0.0.1:8000/admin/. Вы должны увидеть экран входа администратора:
Группа в ВК "Django_Python"
72
Chapter 4: Message Board app
Admin login page
Войдите в систему, введя имя пользователя и пароль, которые вы только что создали. Далее
вы увидите домашнюю страницу администратора Django:
Группа в ВК "Django_Python"
73
Chapter 4: Message Board app
Admin homepage
Но где наше приложение posts ? Оно не отображается на главной странице
администратора!
Нам необходимо явно указать Django, что отображать в админке. К счастью, мы можем
легко изменять это, открыв файл posts/admin.py и отредактировать его следующим
образом:
Группа в ВК "Django_Python"
74
Chapter 4: Message Board app
Code
# posts/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Django теперь знает, что он должен отображать наше posts приложение и его модель базы
данных Post на странице администратора. Если вы обновите свой браузер, вы увидите, что
теперь оно появилось:
Admin homepage updated
Теперь давайте создадим наш первый пост в доске объявлений для нашей базы данных.
Нажмите на кнопку + Add напротив Posts. Введите свой текст в текстовое поле.
Группа в ВК "Django_Python"
75
Chapter 4: Message Board app
Admin new entry
Затем нажмите кнопку "Save", которая перенаправит вас на главную страницу Post. Однако,
если вы посмотрите внимательно, то есть проблема: Наша новая запись называется “Post
object”, что не очень полезно.
Группа в ВК "Django_Python"
76
Chapter 4: Message Board app
Admin new entry
Давайте изменим эту ситуацию. В файле posts/models.py добавьте новую функцию __str__
как в примере:
Code
# posts/models.py
from django.db import models
class Post(models.Model):
text = models.TextField()
def __str__(self):
"""Строковое отображение модели """
return self.text[:��]
Группа в ВК "Django_Python"
77
Chapter 4: Message Board app
Если вы обновите страницу администратора в браузере, вы увидите, что она изменена на
гораздо более наглядное и полезное отображение нашей записи базы данных.
Admin new entry
Гораздо лучше! Рекомендуется добавлять методы str () ко всем моделям, чтобы улучшить
их читаемость.
Views/Templates/URLs
Для того, чтобы отобразить содержимое нашей базы данных на нашей домашней странице,
мы должны подключить наши views, templates и URLConfs. Сейчас этот образец должен
начать казаться знакомым.
Начнем с view. Ранее в книге мы использовали встроенный универсальный TemplateView для отображения файла шаблона на нашей домашней странице. Теперь мы хотим
перечислить содержимое нашей модели базы данных. К счастью, это общая задача в вебразработке и Django поставляется с универсальным основным-классом ListView.
В posts/views.py файле введите код Python ниже:
Группа в ВК "Django_Python"
Chapter 4: Message Board app
78
Code
# posts/views.py
from django.views.generic import ListView
from .models import Post
class HomePageView(ListView):
model = Post
template_name = 'home.html'
В первой строке мы импортируем ListView, а во второй строке нам нужно явно определить,
какую модель мы используем. В view мы создаем подкласс ListView, указываем название
модели и указываем ссылку на шаблон. Внутри ListView возвращает объект с именем
object_list, который мы хотим отобразить в нашем шаблоне (template).
Наш view готов, что означает, что нам все еще нужно настроить наши URL-адреса и сделать
наш шаблон(template). Начнем с шаблона. Создадим каталог(папку) на уровне проекта с
именем templates и файл шаблона home.html.
Command Line
(mb) $ mkdir templates
(mb) $ touch templates/home.html
Затем обновите поле DIRS в settings.py файле, чтобы Django знал, что нужно искать в этой
папке шаблонов.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
79
Code
# settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
В нашем файле шаблона home.html мы можем использовать Django Templating
Language’s(Язык шаблонов Django) для цикла, чтобы перечислить все объекты в
object_list. Помните, что object_list-это то, что ListView возвращает нам.
Code
<!-- templates/home.html -->
<h1>Message board homepage</h1>
<ul>
{% for post in object_list %}
<li>{{ post }}</li>
{% endfor %}
</ul>
Последний шаг заключается в том, чтобы настроить наш URLConfs. Давайте начнем с
файла urls.py на уровне проекта где мы просто подключаем include нашего posts и
добавляем include во вторую строку.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
Code
# mb_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('posts.urls')),
]
Затем создайте файл urls.py на уровне приложения.
Command Line
(mb) $ touch posts/urls.py
И обновите его таким образом:
Code
# posts/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
]
Перезапустите сервер с python manage.py runserver и перейдите на наш сайт
http://127.0.0.1:8000/ в котором теперь перечислены наши сообщения на доске
объявлений.
Группа в ВК "Django_Python"
80
81
Chapter 4: Message Board app
Homepage with posts
В основном мы закончили, но давайте создадим еще несколько сообщений на доске
объявлений в администраторе Django, чтобы убедиться, что они будут отображаться
правильно на главной странице.
Добавление новых записей
Чтобы добавить новые сообщения в нашу доску объявлений, вернитесь в Admin:
http://127.0.0.1:8000/admin/
И создайте еще два поста. Вот как выглядит мой:
Группа в ВК "Django_Python"
82
Chapter 4: Message Board app
Admin entry
Группа в ВК "Django_Python"
83
Chapter 4: Message Board app
Admin entry
Группа в ВК "Django_Python"
84
Chapter 4: Message Board app
Updated admin entries section
Если вы вернетесь на домашнюю страницу, вы увидите, что она автоматически отображает
наши отформатированные сообщения. Ура!
Homepage with three entries
Все работает так, что самое время инициализировать наш каталог, добавить новый код и
Группа в ВК "Django_Python"
Chapter 4: Message Board app
85
и включить наш первый git commit.
Command Line
(mb) $ git init
(mb) $ git add -A
(mb) $ git commit -m 'initial commit'
Tests
Раньше мы тестировали только статические страницы, поэтому мы использовали
SimpleTestCase(простой тест). Но теперь, когда наша домашняя страница работает с базой
данных, нам нужно использовать TestCase, которая позволит нам создать «тестовую» базу
данных, которую мы можем проверить. Другими словами, нам не нужно запускать тесты в
нашей реальной базе данных, но вместо этого можно создать отдельную тестовую базу
данных, заполнить ее образцами данных, а затем протестировать ее.
Начнем с добавления образца записи в текстовое поле базы данных, а затем проверим,
правильно ли она хранится в базе данных. Важно, чтобы все наши методы тестирования
начинались с test_, чтобы Django знал что тестировать! Код будет выглядеть следующим
образом:
Code
# posts/tests.py
from django.test import TestCase
from .models import Post
class PostModelTest(TestCase):
def setUp(self):
Post.objects.create(text='just a test')
Группа в ВК "Django_Python"
86
Chapter 4: Message Board app
def test_text_content(self):
post=Post.objects.get(id= )
expected_object_name = f'{post.text}'
self.assertEqual(expected_object_name, 'just a test')
В верхней части мы импортируем модуль TestCase, который позволяет нам создать образец
базы данных, а затем импортировать нашу Post модель. Мы создаем новый класс
PostModelTest и добавляем метод setUp для создания новой базы данных, которая имеет
только одну запись: сообщение с текстовым полем, содержащим строку 'just a test'.
Затем мы запускаем наш первый тест, test_text_content, чтобы проверить, что поле базы
данных на самом деле содержит только тест. Мы создаем переменную post, которая
представляет первый идентификатор (id) в нашей модели Post. Запомните, что Django
автоматически устанавливает этот id для нас. Если бы мы создали еще одну запись, у нее
был бы идентификатор 2, следующий был бы 3 и так далее.
Следующая строка использует f strings которая является очень классным дополнением к
Python 3.6. Она позволяет помещать переменные непосредственно в строки, если
переменные
окружены
фигурными
скобками
{}.
Здесь
мы
устанавливаем
expected_object_name как строку значения в post.text, который должен быть просто тест.
В последней строке мы используем assertEqual, чтобы проверить, что наша недавно
созданная запись действительно соответствует тому, что мы вводим наверху. Продолжайте
и запустите тест в командной строке python manage.py test.
Группа в ВК "Django_Python"
87
Chapter 4: Message Board app
Command Line
(mb) $ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (
silenced).
.
---------------------------------------------------------------------Ran
test in
.
s
OK
Destroying test database for alias 'default'...
Прошло!
Не волнуйтесь, если предыдущее объяснение было похоже на информационную
перегрузку. Это естественно, когда вы впервые начинаете писать тесты, но вскоре вы
обнаружите, что большинство тестов, которые вы пишете, на самом деле довольно
повторяющиеся.
Время для нашего второго теста. Первый тест был для модели, но теперь мы хотим
проверить нашу единственную страницу: домашнюю страницу (homepage). В частности, мы
хотим проверить, что она существует (throws an HTTP 200 response), использует view home
и использует home.html шаблон(template).
Нам нужно добавить еще один импорт наверху для reverse и совершенно новый класс
HomePageViewTest для нашего теста.
Группа в ВК "Django_Python"
88
Chapter 4: Message Board app
Code
from django.test import TestCase
from django.urls import reverse
from .models import Post
class PostModelTest(TestCase):
def setUp(self):
Post.objects.create(text='just a test')
def test_text_content(self):
post=Post.objects.get(id= )
expected_object_name = f'{post.text}'
self.assertEqual(expected_object_name, 'just a test')
class HomePageViewTest(TestCase):
def setUp(self):
Post.objects.create(text='this is another test')
def test_view_url_exists_at_proper_location(self):
resp = self.client.get('/')
self.assertEqual(resp.status_code,
)
def test_view_url_by_name(self):
resp = self.client.get(reverse('home'))
self.assertEqual(resp.status_code,
)
Группа в ВК "Django_Python"
89
Chapter 4: Message Board app
def test_view_uses_correct_template(self):
resp = self.client.get(reverse('home'))
self.assertEqual(resp.status_code,
)
self.assertTemplateUsed(resp, 'home.html')
Если вы запустите наши тесты снова, вы должны увидеть, что они проходят.
Command Line
(mb) $ python manage.py test
Creating test database for alias 'default'...
System check identified no issues (
silenced).
.
---------------------------------------------------------------------Ran
tests in
.
s
OK
Destroying test database for alias 'default'...
Почему там написано четыре теста? Запомните, что наш setUp метод на самом деле не тест,
он просто позволяет нам запускать последующие тесты. Наши четыре реальных теста это
test_test_content,
test_view_url_exists_at_proper_location,
test_view_url_by_name,
и
test_view_-uses_correct_template.
Любая функция, имеющая в начале слово test* в существующем файле tests.py будет
запущена при выполнении команды python manage.py test.
Мы закончили добавление кода для нашего тестирования, пришло время внести изменения
в git.
Группа в ВК "Django_Python"
90
Chapter 4: Message Board app
Command Line
(mb) $ git add -A
(mb) $ git commit -m 'added tests'
Bitbucket
Нам также нужно сохранить наш код на Bitbucket. Это хорошая привычка, чтобы
сохранить код в случае, если что-нибудь случится с вашим локальным компьютером, и это
также позволяет вам делиться и сотрудничать с другими разработчиками.
У Вас уже должна быть учетная запись Bitbucket из главы 3, поэтому создайте новый
репозиторий, который мы назовем mb-app.
Bitbucket create app
На следующей странице нажмите на нижнюю ссылку “I have an existing project”.
Скопируйте две команды для подключения, а затем нажмите repository to Bitbucket.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
91
Это должно выглядеть так, замените wsvincent (мое имя пользователя)на ваш логин в
системе bitbucket :
Command Line
(mb) $ git remote add origin git@bitbucket.org:wsvincent/mb-app.git
(mb) $ git push -u origin master
Heroku configuration
Вы также должны уже иметь настройки учетной записи Heroku установленные из главы 3.
Нам необходимо внести следующие изменения в наш проект доски объявлений, чтобы
развернуть его в интернете:
• обновить Pipfile.lock
• новый Procfile
• установить gunicorn
• обновить settings.py
В вашем Pipfile укажите версию Python мы используем �.�. Добавьте эти две строки в
конец файла.
Code
# Pipfile
[requires]
python_version = " . "
Запустите pipenv lock для создания соответствующего Pipfile.lock.
Группа в ВК "Django_Python"
Chapter 4: Message Board app
Command Line
(mb) $ pipenv lock
Затем создайте Procfile, который указывает Heroku, как запустить удаленный сервер, где
наш код будет работать.
Command Line
(mb) $ touch Procfile
Теперь мы укажем Heroku использовать gunicorn в качестве нашего рабочего сервера и
посмотреть в наш mb_project.wsgi файл для получения дальнейших инструкций.
Command Line
web: gunicorn mb_project.wsgi --log-file -
Далее установим gunicorn который мы будем использовать для production но при этом
используя внутренний сервер Django для локальной разработки.
Command Line
(mb) $ pipenv install gunicorn
Наконец, обновите ALLOWED_HOSTS в нашем файле settings.py
file. Code
# mb_project/settings.py
ALLOWED_HOSTS = ['*']
Все мы закончили! Добавьте и зафиксируйте наши новые изменения в git, а затем
отправьте их в Bitbucket.
Группа в ВК "Django_Python"
92
93
Chapter 4: Message Board app
Command Line
(mb) $ git status
(mb) $ git add -A
(mb) $ git commit -m 'New updates for Heroku deployment'
(mb) $ git push -u origin master
Heroku развертывание
Убедитесь, что вы вошли в свою учетную запись Heroku.
Command Line
(mb) $ heroku login
Затем запустите команду heroku create и Heroku случайным образом сгенерирует для вас
имя приложения. Вы сможете настроить это позже, если будет необходимо.
Command Line
(mb) $ heroku create
Creating app... done,
https://agile-inlet-
agile-inlet.herokuapp.com/ | https://git.heroku.com/agile-inlet-
.git
Настройте git на использование имени вашего нового приложения, когда вы отправляете
код на Heroku. Мое сгенерированное имя Heroku это agile-inlet-����� поэтому
команда выглядит следующим образом.
Группа в ВК "Django_Python"
\
94
Chapter 4: Message Board app
Command Line
(mb) $ heroku git:remote -a agile-inlet-
Укажите Heroku игнорировать статические файлы, которые мы подробно рассмотрим при
развертывании нашего приложения блога в книге позже.
Command Line
(mb) $ heroku config:set DISABLE_COLLECTSTATIC=
Отправьте код в Heroku и добавьте бесплатное масштабирование, чтобы он действительно
работал в интернете, иначе код просто сидит там.
Command Line
(mb) $ git push heroku master
(mb) $ heroku ps:scale web=
Если вы откроете новый проект heroku open, он автоматически запустит новое окно
браузера с URL вашего приложения. Мой находится по адресу:
https://agile-inlet-25811.herokuapp.com/.
Live site
Группа в ВК "Django_Python"
Chapter 4: Message Board app
95
Вывод
На данный момент мы создали, протестировали и развернули наше первое приложение на
основе базы данных. Хотя это намеренно довольно просто, теперь мы знаем, как создать
модель базы данных, обновить ее с помощью панели администратора, а затем отобразить
содержимое на веб-странице. Но чего-то не хватает, не так ли?
В реальном мире пользователям нужны формы для взаимодействия с нашим сайтом. Ведь
не у всех должен быть доступ к админ панели. В следующей главе мы создадим приложение
блога, которое использует формы, чтобы пользователи могли создавать, редактировать и
удалять записи. Мы также добавим стили CSS.
Группа в ВК "Django_Python"
ϏҵҪҬҪ�:Blogapp ҹҺҲҵҸҰүҷҲүύҵҸҭ
ώ ӇҼҸҳ ҭҵҪҬү ҶӅ ҹҸһҼҺҸҲҶ ҹҺҲҵҸҰүҷҲү ҴҸҼҸҺҸү ҹҸұҬҸҵӉүҼ ҹҸҵӆұҸҬҪҼүҵӉҶ һҸұҮҪҬҪҼӆ ҺүҮҪҴҼҲҺҸҬҪҼӆ Ҳ ҽҮҪҵӉҼӆ һҸҸҫӃүҷҲӉ ϙҪ ҭҵҪҬҷҸҳ һҼҺҪҷҲӀү ҫҽҮҽҼ ҹүҺүӁҲһҵүҷӅ Ҭһү
һҸҸҫӃүҷҲӉ Ҭ ҫҵҸҭү Ҳ ҮҵӉ ҴҪҰҮҸҭҸ ҸҼҮүҵӆҷҸҭҸ һҸҸҫӃүҷҲӉ ҫҽҮүҼ ҬӅҮүҵүҷҪ ҸҼҮүҵӆҷҪӉ
һҼҺҪҷҲӀҪϘӅҼҪҴҰүҹҸұҷҪҴҸҶҲҶһӉһ$44ҮҵӉһҼҲҵҲұҪӀҲҲҲҽұҷҪүҶ ҴҪҴ%KBOHPҺҪҫҸҼҪүҼһҸ
һҼҪҼҲӁүһҴҲҶҲҾҪҳҵҪҶҲ
ϙҪӁҪҵӆҷҪӉҷҪһҼҺҸҳҴҪ
Как описано в предыдущих главах, наши шаги для создания нового проекта Django будут
выглядеть следующим образом:
• Создать новую папку для нашего проекта на рабочем столе с именем blog
• Установить Django в новой виртуальной среде
• Создать новый проект Django с именем blog_project
• Создать новое приложение blog
• Выполнить миграцию для установки базы данных
• Обновить settings.py
Выполните следующие команды в новой консоли командной строки. Обратите внимание,
что фактическое имя виртуальной среды будет (blog-XXX), где XXX представляет
случайные символы. Я использую здесь (blog) , чтобы было проще, так как мое имя будет
отличаться от вашего.
И не забудьте указать пробел с точкой ". " в конце команды для создания нашего нового
blog_project. (прм. переводчика. Создает проект Django в существующей директории без
создания новой папки, не обязательно)
Группа в ВК "Django_Python"
97
Chapter 5: Blog app
Command Line
$ cd ~/Desktop
$ mkdir blog
$ cd blog
$ pipenv install django
$ pipenv shell
(blog) $ django-admin startproject blog_project .
(blog) $ python manage.py startapp blog
(blog) $ python manage.py migrate
(blog) $ python manage.py runserver
Чтобы убедиться, что Django знает о нашем новом приложении, откройте текстовый
редактор и добавьте новое приложение в INSTALLED_APPS в нашем settings.py файле:
Code
# blog_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog', # new
]
Если вы перейдете по http://127.0.0.1:8000/ должны увидеть следующую страницу.
Группа в ВК "Django_Python"
98
Chapter 5: Blog app
Django welcome page
Хорошо, первичная настройка закончена! Далее мы создадим модель базы данных для
записей блога.
Database Models(модели базы данных)
Каковы характеристики типичного приложения для блога? В нашем случае
давайте придерживаться простоты и предположим, что у каждого сообщения есть
название, автор и тело. Мы можем превратить это в модель базы данных, откроем
файл blog/models.py и введем показанный ниже код :
Группа в ВК "Django_Python"
99
Chapter 5: Blog app
Code
# blog/models.py
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=
)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
В верхней части мы импортируем класс models а затем создаем подкласс models.Model с
именем Post. Используя функционал подкласса, мы автоматически имеем доступ ко всему
в
django.db.models.Models и можем добавлять дополнительные поля и методы по
своему желанию.
Для title мы ограничиваем длину до 200 символов, а для body мы используем текстовое
поле, которое будет автоматически расширяться по мере необходимости, чтобы
соответствовать тексту пользователя. В Django доступно много типов полей; вы можете
увидеть полный список здесь.
Для поля author мы используем ForeignKey это предоставляет связь многие-к-одному .
Это означает, что данный пользователь может быть автором многих различных постов в
блоге, но не наоборот. Ссылка на встроенную модель User которой Django обеспечивает
аутентификацию. Для всех связей многие-к-одному таких как ForeignKey нам также
необходимо указать параметр on_delete .
Группа в ВК "Django_Python"
100
Chapter 5: Blog app
Теперь, когда наша новая модель базы данных создана, нам нужно создать для нее новую
запись миграции и перенести изменения в нашу базу данных. Это двухэтапный процесс и
может быть выполнен следующими командами:
Command Line
(blog) $ python manage.py makemigrations blog
(blog) $ python manage.py migrate blog
Наша база настроена! Что дальше?
Admin
Нам нужен способ доступа к нашим данным. Войдем в Django админ! Но сначала создадим
учетную запись суперпользователя, введя приведенную ниже команду и после отвечая на
запросы введем адрес электронной почты и пароль. Обратите внимание, что при вводе
пароля он не будет отображаться на экране по соображениям безопасности.
Command Line
(blog) $ python manage.py createsuperuser
Username (leave blank to use 'wsv'): wsv
Email:
Password:
Password (again):
Superuser created successfully.
Теперь снова запустите сервер Django с помощью команды python manage.py runserver и
откройте Django админ http://127.0.0.1:8000/admin/. Войдите с новой учетной
записью суперпользователя.
Упс! А где наша новая Post модель?
Группа в ВК "Django_Python"
101
Chapter 5: Blog app
Admin homepage
Мы забыли обновить blog/admin.py так что давайте сейчас сделаем это.
Code
# blog/admin.py
from django.contrib import admin
from .models import Post
admin.site.register(Post)
Если вы обновите страницу, вы увидите это обновление.
Группа в ВК "Django_Python"
102
Chapter 5: Blog app
Admin homepage
Давайте добавим два сообщения в блог, чтобы у нас были примеры данных для работы.
Нажмите кнопку + Add рядом с Posts чтобы создать новую запись. Не забудьте добавить
“author” к каждому сообщению, так как по умолчанию все поля модели обязательны для
заполнения. Если вы попытаетесь ввести сообщение без автора вы увидите ошибку. Если
мы захотим изменить это, мы можем добавить field options(параметры поля) в нашу
модель, чтобы сделать это поле необязательным или заполнить его значением по
умолчанию
Группа в ВК "Django_Python"
103
Chapter 5: Blog app
Первый пост
Группа в ВК "Django_Python"
104
Chapter 5: Blog app
Второй пост
Группа в ВК "Django_Python"
105
Chapter 5: Blog app
Админка с двумя постами
Теперь, когда наша модель базы данных завершена, нам нужно создать необходимые view,
URL-адреса и шаблоны, чтобы мы могли отображать информацию в нашем вебприложении.
URLs
Мы хотим, чтобы сообщения в блоге отображались на главной странице, поэтому, как и в
предыдущих главах, мы сначала настроим URLConfs уровня проекта, а затем URLConfs
уровня приложения, что бы достичь этого. Обратите внимание на то, что “уровень
проекта” означает в той же родительской папке где папка blog_project и папка приложения
blog.
В командной строке остановите существующий сервер с помощью Control-c и создайте
новый urls.py файл в вашем blog:
Группа в ВК "Django_Python"
106
Chapter 5: Blog app
Command Line
(blog) $ touch blog/urls.py
Теперь обновите его с помощью кода ниже.
Code
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.BlogListView.as_view(), name='home'),
]
Мы импортируем views (которые скоро создадим) в верхней части. Пустая строка ''
говорит Python что соответствует всем значениям, далее мы делаем URL именованным
home, к которому мы можем обратиться в наших views позже. Хотя это не обязательно но
добавление имени к URL это хорошая практика которую необходимо принять так как это
помогает сохранять организованность когда количество ваших URL растет.
Также мы должны обновить файл urls.py на уровне проекта, чтобы он мог пересылать все
запросы непосредственно на blog приложение.
Группа в ВК "Django_Python"
107
Chapter 5: Blog app
Code
# blog_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('', include('blog.urls')),
]
Мы добавили include во второй строке и url образец использовав пустую строку
регулярного выражения '' указывающее, что URL запросы должны быть перенаправлены
на URL-адреса блога(blog) для дальнейших инструкций.
Views
Мы собираемся использовать views на основе классов, но если вы хотите увидеть
функциональный способ создания приложения для блога, я настоятельно рекомендую
Django Girls Tutorial. Это отличный учебник.
В нашем файле views добавьте код ниже, чтобы отобразить содержимое нашей модели Post
с помощью ListView.
Группа в ВК "Django_Python"
108
Chapter 5: Blog app
Code
# blog/views.py
from django.views.generic import ListView
from . models import Post
class BlogListView(ListView):
model = Post
template_name = 'home.html'
ώҮҬҽҿҬүҺҿҷҲҿһҼҺҸҴҪҿҶӅҲҶҹҸҺҼҲҺҽүҶ-JTU7JFXҲҷҪӂҽҶҸҮүҵӆҫҪұӅҮҪҷҷӅҿ1PTUϓҪҼүҶ
ҶӅһҸұҮҪүҶҹҸҮҴҵҪһһ-JTU7JFXҲҮҸҫҪҬҵӉүҶһһӅҵҴҲҷҪҷҪӂҽҶҸҮүҵӆҲӂҪҫҵҸҷҧҼҸӇҴҸҷҸҶҲҼ
ҷҪҶҶҷҸҭҸҴҸҮҪҹҸһҺҪҬҷүҷҲӈһҺүҪҵҲұҪӀҲүҳҬһүҭҸӇҼҸҭҸһҷҽҵӉ
Templates ӂҪҫҵҸҷӅ
ϞүҹүҺӆ һ ҷҪӂҲҶ 63-$POGT Ҳ WJFXT ұҪҴҸҷӁҲҵҲ ҷҪҶ ҷү ҿҬҪҼҪүҼ ҼҸҵӆҴҸ ҼҺүҼӆүҳ ӁҪһҼҲ
ҭҸҵҸҬҸҵҸҶҴҲӂҪҫҵҸҷҸҬ UFNQMBUFT ϖҪҴҶӅҽҰүузнали изҭҵҪҬы ҶӅҶҸҰүҶҷҪһҵүҮҸҬҪҼӆҸҼ
ҮҺҽҭҲҿ ӂҪҫҵҸҷҸҬ ӁҼҸҫӅ ҮүҺҰҪҼӆ наш ҴҸҮ Ҭ ӁҲһҼҸҼү ϛҸӇҼҸҶҽ ҷҪӁҷүҶ һ ҾҪҳҵҪ CBTFIUNM Ҳ
ҾҪҳҵҪ IPNFIUNM ҴҸҼҸҺӅҳ ҷҪһҵүҮҽүҼһӉ ҸҼ ҷүҭҸ ϛҸұҰү ҴҸҭҮҪ ҶӅ ҮҸҫҪҬҲҶ ӂҪҫҵҸҷӅ ҮҵӉ
һҸұҮҪҷҲӉҲҺүҮҪҴҼҲҺҸҬҪҷҲӉһҸҸҫӃүҷҲҳҫҵҸҭҪ ҸҷҲҼҪҴҰүҶҸҭҽҼҷҪһҵүҮҸҬҪҼӆһӉҸҼbase.html.
Начнем с создания каталога шаблонов(templates) на уровне проекта с двумя файлами
шаблонов.
Группа в ВК "Django_Python"
109
Chapter 5: Blog app
Command Line
(blog) $ mkdir templates
(blog) $ touch templates/base.html
(blog) $ touch templates/home.html
Затем обновите settings.py чтобы Django знал, где искать наши шаблоны.
Code
# blog_project/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
},
]
Теперь обновите шаблон base.html следующим образом.
Code
<!-- templates/base.html -->
<html>
<head>
<title>Django blog</title>
</head>
<body>
<header>
<h1><a href="/">Django blog</a></h1>
</header>
Группа в ВК "Django_Python"
110
Chapter 5: Blog app
<div class="container">
{% block content %}
{% endblock content %}
</div>
</body>
</html>
Обратите внимание на то, что код между {% block content %} и {% endblock content %} может
быть заполнен другими шаблонами. Говоря об этом, вот код для home.html.
Code
<!-- templates/home.html -->
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post-entry">
<h2><a href="">{{ post.title }}</a></h2>
<p>{{ post.body }}</p>
</div>
{% endfor %}
{% endblock content %}
В верхней части отметим, что этот шаблон расширяет(extends) base.html и обертывает
нужный вам код с помощью контент-блоков. Мы используем язык шаблонов Django
Templating Language, чтобы создать простой цикл for для каждой записи блога. Обратите
внимание, что object_list происходит из ListView и содержит все объекты в нашем view.
Если вы снова запустите сервер Django: python manage.py runserver.
Группа в ВК "Django_Python"
111
Chapter 5: Blog app
И обновите http://127.0.0.1:8000/ мы видим, что это работает.
Главная страница блога с двумя постами
Но выглядит это ужасно. Давайте это исправим!
Static files(статичные файлы)
Нам нужно добавить CSS, который называется статическим файлом, потому что, в отличие
от нашего динамического контента базы данных, он не изменяется. К счастью добавлять,
статические файлы, такие как CSS, JavaScript и изображения в наш проект Django очень
просто.
В готовом к производству Django проекте вы, как правило, храните его в сети доставки
контента (CDN) для лучшей производительности, но для наших целей хранение файлов
локально это нормально.
Сначала закройте наш локальный сервер с Control-c. Затем создайте папку на уровне
проекта с именем static.
Группа в ВК "Django_Python"
112
Chapter 5: Blog app
Command Line
(blog) $ mkdir static
Как и в нашей папке с шаблонами, нам нужно обновить settings.py, чтобы сообщить Django,
где искать эти статические файлы. Мы можем обновить settings.py с изменением строки для
STATICFILES_DIRS. Добавьте его в нижнюю часть файла под заголовком STATIC_URL.
Code
# blog_project/settings.py
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
Теперь создайте папку css в static и добавьте в нее новый файл base.css.
Command Line
(blog) $ mkdir static/css
(blog) $ touch static/css/base.css
Что мы должны поместить в ваш файл? Как насчет изменения title на красный?
Code
/* static/css/base.css */
header h1 a {
color: red;
}
Последний шаг. Нам нужно добавить статические файлы в ваши шаблоны, добавив {% load
staticfiles %} в начало base.html. Потому что другие наши шаблоны наследуются от base.html
мы должны добавить это только один раз. Добавьте новую строку в нижней части кода
<head>< / head>, которая явно ссылается на наш новый файл base.css.
Группа в ВК "Django_Python"
113
Chapter 5: Blog app
Code
<!-- templates/base.html -->
{% load static %}
<html>
<head>
<title>Django blog</title>
<link rel="stylesheet" href="{% static 'css/base.css' %}">
</head>
...
УФ! Это было немного больно, но это одноразовая боль. Теперь мы можем добавить
статические файлы в нашу папку static, и они автоматически появятся во всех наших
шаблонах.
Запустите сервер снова с python manage.py runserver и посмотрите на нашем обновленном
сайте http://127.0.0.1:8000/.
Домашняя страница блога с красным заголовком
Мы можем сделать немного лучше. Как насчет того, чтобы добавить пользовательский
шрифт и еще немного CSS? Поскольку эта книга не является учебником по CSS, просто
вставьте следующее между тегами <head>< / head>, чтобы добавить Source Sans Pro,
бесплатный шрифт от Google.
Группа в ВК "Django_Python"
114
Chapter 5: Blog app
Code
<!-- templates/base.html -->
{% load static %}
<html>
<head>
<title>Django blog</title>
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:
stylesheet">
<link rel="stylesheet" href="{% static 'css/base.css' %}">
</head>
...
Затем обновите наш css файл, скопировав и вставив следующий код:
Code
/* static/css/base.css */
body {
font-family: 'Source Sans Pro', sans-serif;
font-size:
px;
}
header {
border-bottom:
px solid #
margin-bottom:
rem;
;
display: flex;
}
header h1 a {
color: red;
Группа в ВК "Django_Python"
" rel="\
115
Chapter 5: Blog app
text-decoration: none;
}
.nav-left {
margin-right: auto;
}
.nav-right {
display: flex;
padding-top:
rem;
}
.post-entry {
margin-bottom:
rem;
}
.post-entry h2 {
margin:
. rem
;
}
.post-entry h2 a,
.post-entry h2 a:visited {
color: blue;
text-decoration: none;
}
.post-entry p {
margin:
;
Группа в ВК "Django_Python"
116
Chapter 5: Blog app
font-weight:
;
}
.post-entry h2 a:hover {
color: red;
}
Обновить домашнюю страницу http://127.0.0.1:8000/ и вы должны увидеть следующее.
Домашняя страница блога с CSS
Отдельные страницы блога
Теперь мы можем добавить функциональность для отдельных страниц блога. Как мы
можем это сделать?Мы должны создать новое представление, URL и шаблон. Я надеюсь,
что вы заметили шаблон в разработке с Django сейчас!
Начните с представления. Для упрощения можно использовать общее представление
DetailView на основе классов. В верхней части файла добавьте DetailView в список импорта,
а затем создайте наше новое представление под названием BlogDetailView.
Группа в ВК "Django_Python"
117
Chapter 5: Blog app
view called BlogDetailView.
Code
# blog/views.py
from django.views.generic import ListView, DetailView
from . models import Post
class BlogListView(ListView):
model = Post
template_name = 'home.html'
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
В этом новом представлении мы определяем модель, которую мы используем, Post и
шаблон, с которым мы хотим ее связать, post_detail.html. По умолчанию DetailView
предоставит контекстный объект, который мы можем использовать в нашем шаблоне,
называемый либо объектом, либо строчным именем нашей модели post. Кроме того,
DetailView ожидает либо первичный ключ, либо slug, переданный ему в качестве
идентификатора. Подробнее об этом вкратце.
Теперь выйдите из локального сервера Control-c и создайте наш новый шаблон для деталей
поста следующим образом:
Группа в ВК "Django_Python"
118
Chapter 5: Blog app
Command Line
(blog) $ touch templates/post_detail.html
Затем введите следующий код:
Code
<!-- templates/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ post.title }}</h2>
<p>{{ post.body }}</p>
</div>
{% endblock content %}
В верхней части мы указываем, что этот шаблон наследуется от base.html. Затем отобразите
title и body из нашего объекта контекста, который DetailView делает доступным как post.
Лично я нашел именование объектов контекста в общих представлениях чрезвычайно
запутанным при первом изучении Django. Поскольку наш объект контекста из подробного
представления является либо вашим именем модели post, либо объектом, мы также можем
обновить наш шаблон следующим образом, и он будет работать точно так же.
Группа в ВК "Django_Python"
119
Chapter 5: Blog app
Code
<!-- templates/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>{{ object.body }}</p>
</div>
{% endblock content %}
Если вы обнаружите, что использование post или object сбивает с толку, мы также можем
явно задать имя объекта контекста в нашем представлении. Поэтому, если бы мы хотели
назвать его anything_you_want, а затем использовать его в шаблоне, код выглядел бы
следующим образом, и он работал бы так же.
Code
# blog/views.py
...
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
context_object_name = 'anything_you_want'
Группа в ВК "Django_Python"
120
Chapter 5: Blog app
Code
<!-- templates/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ anything_you_want.title }}</h2>
<p>{{ anything_you_want.body }}</p>
</div>
{% endblock content %}
"Волшебное" именование объекта контекста-это цена, которую вы платите за простоту и
удобство использования общих представлений. Они великолепны, если вы знаете, что они
делают, но их трудно настроить, если вы хотите другого поведения.
Хорошо, что будет дальше? Как насчет добавления нового URLConf для нашего
представления, который мы можем сделать следующим образом.
Code
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.BlogListView.as_view(), name='home'),
path('post/<int:pk>/', views.BlogDetailView.as_view(), name='post_detail'),
]
Группа в ВК "Django_Python"
121
Chapter 5: Blog app
Все записи в блоге будут начинаться с post/. Далее идет первичный ключ для нашей записи
post, которая будет представлена в виде целого числа <int: pk>. Вероятно вы спросите что
это за первичный ключ? Django автоматически добавляет автоматически увеличивающийся
первичный ключ к нашим моделям баз данных. Таким образом, как только мы объявили
название поля, author и body в нашей модели Post, Django под капотом также добавил еще
одно поле под названием id, который является нашим первичным ключом. Мы можем
получить к нему доступ как id или pk.
Этот pk для нашего первого поста "Привет, Мир" равен 1. Для второго поста это 2. и так
далее. Поэтому, когда мы переходим на страницу отдельной записи для нашего первого
сообщения, мы можем ожидать, что его url шаблон будет post/1.
Примечание: понимание того, как первичные ключи работают с DetailView является очень
распространенной путаницей для начинающих. Стоит перечитать предыдущие два абзаца
несколько раз, если не понимаете. С практикой это станет второй натурой.
Если теперь запустить сервер с python manage.py runserver и перейти непосредственно к
http://127.0.0.1:8000/post/1/ вы увидите специальную страницу для нашего первого
поста в блоге.
Blog post one detail
Ура! Вы также можете перейти к http://127.0.0.1:8000/post/2 посмотреть вторую запись.
Чтобы сделать нашу жизнь проще, мы должны обновить ссылку на главной странице,
чтобы мы могли напрямую получить доступ к отдельным сообщениям в блоге оттуда. В
настоящее время в home.html наша ссылка пуста: <a href="">. Обновите его до
<a href="{% url 'post_detail' post.pk %}">.
Группа в ВК "Django_Python"
122
Chapter 5: Blog app
Code
<!-- templates/home.html -->
{% extends 'base.html' %}
{% block content %}
{% for post in object_list %}
<div class="post-entry">
<h2><a href="{% url 'post_detail' post.pk %}">{{ post.title }}</a></h2>
<p>{{ post.body }}</p>
</div>
{% endfor %}
{% endblock content %}
Мы начинаем с того, что говорим нашему шаблону Django, что мы хотим ссылаться на
URLConf, используя код {%url ... %}. Какой URL? Тот, который называется post_detail,
который мы назвали BlogDetailView в нашей url-конфигурации всего минуту назад. Если
мы посмотрим на post_detail в нашем URLConf, мы увидим, что он ожидает, что будет
передан аргумент pk, представляющий первичный ключ для записи блога. К счастью,
Django уже создал и включил это поле pk в наш объект post. Мы передаем его в URLConf,
добавляя его в шаблон как post.pk.
Чтобы убедиться, что все работает, обновите главную страницу http://127.0.0.1:8000/ и
нажмите на название каждого поста в блоге, чтобы подтвердить работу новых ссылок.
Тесты
Сейчас нам нужно протестировать нашу модель и представления. Мы хотим убедиться, что
модель Post работает должным образом, включая ее представление. И мы хотим
протестировать как ListView, так и DetailView.
Группа в ВК "Django_Python"
123
Chapter 5: Blog app
Вот как выглядят примеры тестов в файле blog/tests.py.
Code
# blog/tests.py
from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse
from .models import Post
class BlogTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(
username='testuser',
email='test@email.com',
password='secret'
)
self.post = Post.objects.create(
title='A good title',
body='Nice body content',
author=self.user,
)
def test_string_representation(self):
post = Post(title='A sample title')
self.assertEqual(str(post), post.title)
Группа в ВК "Django_Python"
124
Chapter 5: Blog app
def test_post_content(self):
self.assertEqual(f'{self.post.title}', 'A good title')
self.assertEqual(f'{self.post.author}', 'testuser')
self.assertEqual(f'{self.post.body}', 'Nice body content')
def test_post_list_view(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code,
)
self.assertContains(response, 'Nice body content')
self.assertTemplateUsed(response, 'home.html')
def test_post_detail_view(self):
response = self.client.get('/post/ /')
no_response = self.client.get('/post/
/')
self.assertEqual(response.status_code,
)
self.assertEqual(no_response.status_code,
)
self.assertContains(response, 'A good title')
self.assertTemplateUsed(response, 'post_detail.html')
В этих тестах много нового, поэтому мы будем проходить их медленно. Вверху
импортируем get_user_model для ссылки на активного пользователя. Мы импортируем
TestCase, который мы видели раньше, а также Client (), который является новым и
используется в качестве фиктивного веб-браузера для имитации GET и POST запросов на
URL. Другими словами, всякий раз, когда вы тестируете представления, вы должны
использовать Client().
В нашем методе setUp мы добавляем образец поста в блоге для тестирования, а затем
подтверждаем, что его строковое представление и содержимое верны. Затем мы
используем test_post_list_view, чтобы подтвердить, что наш сайт возвращает код статуса
HTTP 200, содержит наш текст, и использует правильный шаблон home.html.
Группа в ВК "Django_Python"
125
Chapter 5: Blog app
Наконец test_post_detail_view проверяет, что наша страница работает должным образом и
что неправильная страница возвращает 404. Всегда хорошо проверить, что что-то
существует, и что что-то неправильное не существует в ваших тестах.
Продолжайте и выполните эти тесты сейчас. Они все должны быть пройдены
Command Line
(testy) $ python manage.py test
Git
Сейчас самое время для нашего первого git commit. Сначала инициализируйте
наш каталог.Command Line
(testy) $ git init
Затем просмотрите все содержимое, которое мы добавили, проверив состояние. Добавьте
все новые файлы. И сделайте наш первый commit.
Command Line
(testy) $ git status
(testy) $ git add -A
(testy) $ git commit -m 'initial commit'
Conclusion
Мы создаем простое приложение блог с нуля! С помощью администратора Django мы
можем создавать, редактировать или удалять контент. И мы использовали DetailView
впервые создав детальное отдельное представление каждого поста блога.
Группа в ВК "Django_Python"
126
Chapter 5: Blog app
В следующем разделе Глава 6: Приложение блога с формами мы добавим формы, чтобы
нам вообще не пришлось использовать администратора Django для этих изменений.
Группа в ВК "Django_Python"
Глава 6: Формы
В этой главе мы продолжим работу над нашим приложением блога из главы 5, добавив
формы, чтобы пользователь мог создавать, редактировать или удалять любую из своих
записей блога.
Формы
Формы очень распространены и очень сложны для правильной реализации. Каждый раз,
когда вы принимаете пользовательский ввод, возникают проблемы безопасности (XSS
Атаки), требуется правильная обработка ошибок, а также вопросы пользовательского
интерфейса о том, как предупредить пользователя о проблемах с формой. Не говоря уже о
необходимости перенаправления при успехе.
К счастью для нас, встроенные формы Django абстрагируют большую часть сложности и
предоставляют богатый набор инструментов для обработки распространенных случаев
использования, работающих с формами.
Чтобы начать, обновите наш базовый шаблон, чтобы отобразить ссылку на страницу для
ввода новых сообщений в блоге. Он примет фрму <a href= "{% url 'post_new'%} " ></a>, где
post_new-это имя нашего URL.
Обновленный файл должен выглядеть следующим образом:
Группа в ВК "Django_Python"
128
Chapter 6: Forms
Code
<!-- templates/base.html -->
{% load staticfiles %}
<html>
<head>
<title>Django blog</title>
<link href="https://fonts.googleapis.com/css?family=Source+Sans+Pro:
="stylesheet">
<link rel="stylesheet" href="{% static 'css/base.css' %}">
</head>
<body>
<div class="container">
<header>
<div class="nav-left">
<h1><a href="/">Django blog</a></h1>
</div>
<div class="nav-right">
<a href="{% url 'post_new' %}">+ New Blog Post</a>
</div>
</header>
{% block content %}
{% endblock content %}
</div>
</body>
</html>
Давайте добавим новый URLConf для post_new:
Группа в ВК "Django_Python"
" rel\
129
Chapter 6: Forms
Code
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.BlogListView.as_view(), name='home'),
path('post/<int:pk>/', views.BlogDetailView.as_view(), name='post_detail'),
path('post/new/', views.BlogCreateView.as_view(), name='post_new'),
]
Ваш url будет начинаться с post / new/, представление называется Blog Create View, и url
будет называться post_new. Просто, правда?
Теперь давайте создадим наше представление, импортировав новый универсальный класс
под названием Create View, а затем создадим его подкласс для создания нового
представления с именем BlogCreateView.
Code
# blog/views.py
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView
from . models import Post
class BlogListView(ListView):
model = Post
template_name = 'home.html'
Группа в ВК "Django_Python"
130
Chapter 6: Forms
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = '__all__'
В BlogCreateView мы указываем нашу модель базы данных Post, имя нашего шаблона
post_new.html и все поля с '__all__', так как у нас только два: title и author. Последний шаг создать наш шаблон, который мы назовем post_new.html.
Command Line
(blog) $ touch templates/post_new.html
А затем добавьте следующий код:
Группа в ВК "Django_Python"
131
Chapter 6: Forms
Code
<!-- templates/post_new.html -->
{% extends 'base.html' %}
{% block content %}
<h1>New post</h1>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Save" />
</form>
{% endblock %}
Давайте разберемся с тем, что мы сделали:
• В верхней строке мы наследуем от нашего базового шаблона.
• Используются HTML-теги <form> с методом POST, так как мы отправляем данные.
Если бы мы получали данные из формы, например, в окне поиска, мы бы
использовали GET.
• Добавлен {% csrf_token %}, который предоставляется Django для защиты нашей
формы от атак межсайтового скриптинга. Вы должны использовать его для всех
ваших форм в Django.
• Затем для вывода данных формы используется {{ form.as_p }}, который отображает
его в тегах параграфа <p>.
• Наконец, указываем тип ввода submit и присваиваем ему значение "Save".
Для просмотра нашей работы запустите сервер с python manage.py runserver и перейдите на
домашнюю страницу по адресу http://127.0.0.1:8000/.
Группа в ВК "Django_Python"
132
Chapter 6: Forms
Homepage with New button
Нажмите на нашу ссылку "+ New Blog Post", которое перенаправит вас
на: http://127.0.0.1:8000/post/new/.
Группа в ВК "Django_Python"
133
Chapter 6: Forms
Blog new page
Попробуйте создать новую запись в блоге и отправить ее.
Группа в ВК "Django_Python"
134
Chapter 6: Forms
Blog new page
Упс! что случилось?
Группа в ВК "Django_Python"
135
Chapter 6: Forms
Blog new page
Сообщение об ошибке Django является весьма полезным. Он жалуется, что мы не указали,
куда отправить пользователя после успешной отправки формы. Давайте отправим
пользователя на страницу сведений после успешной отправки; таким образом они смогут
увидеть свою завершенную публикацию.
Мы можем следовать предложению Django и добавить get_absolute_url в нашу модель. Это
лучшая практика, которую вы всегда должны делать. Он устанавливает канонический URLадрес для объекта, поэтому, даже если структура ваших URL-адресов изменится в будущем,
ссылка на конкретный объект будет одинаковой. Короче говоря, вы должны добавить
get_absolute_url() и __ str_ _ () метод к каждой модели, которую вы пишете.
Группа в ВК "Django_Python"
136
Chapter 6: Forms
Откройте models.py файл. Добавьте импорт во второй строке для reverse и новый метод
get_-absolute_url.
Command Line
# blog/models.py
from django.db import models
from django.urls import reverse
class Post(models.Model):
title = models.CharField(max_length=
)
author = models.ForeignKey(
'auth.User',
on_delete=models.CASCADE,
)
body = models.TextField()
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('post_detail', args=[str(self.id)])
Reverse - очень удобная утилита Django, позволяющая ссылаться на объект по имени
шаблона URL, в данном случае post_detail. Если вы всмните наш шаблон URL, то он
выглядит следующим образом:
Группа в ВК "Django_Python"
137
Chapter 6: Forms
Code
path('post/<int:pk>/', views.BlogDetailView.as_view(), name='post_detail'),
Это означает, что для того, чтобы этот маршрут работал, мы должны также передать
аргумент с ключом pk или первичным ключом объекта. Запутанно что pk и id
взаимозаменяемы в Django, хотя документация Django рекомендуют использовать self.id с
параметром get_absolute_url.
Поэтому мы сообщаем Django, что конечным
местоположением записи Post является ее представление post_detail, которое представляет
собой posts / <int: pk> /, поэтому маршрут для первой созданной нами записи будет
находиться в posts / 1.
Попробуйте создать новую запись в блоге еще раз по адресу http://127.0.0.1:8000/post/new/,
и в случае успеха вы будете перенаправлены на страницу подробного просмотра, где
размещена запись.
Новая страница блога с вводом
Группа в ВК "Django_Python"
138
Chapter 6: Forms
Вы также заметите, что наш предыдущий пост в блоге тоже есть. Он был успешно
отправлен в базу данных, но Django не знал, как перенаправить нас после этого.
Blog homepage with four posts
Хотя мы можем обратиться к администратору Django, чтобы удалить нежелательные
сообщения, но лучше добавить формы, чтобы пользователь мог обновлять и удалять
существующие сообщения непосредственно с сайта.
Форма обновления
Процесс создания формы обновления, чтобы пользователи могли редактировать
сообщения в блоге, должен быть знакомым. Мы снова будем использовать встроенное
общее представление на основе классов Django UpdateView и создадим необходимый
шаблон, URL и представление.
Группа в ВК "Django_Python"
139
Chapter 6: Forms
Для начала добавим новую ссылку на post_detail.html, чтобы возможность редактирования
сообщения блога появилась на отдельной странице блога.
Code
<!-- templates/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>{{ object.body }}</p>
</div>
<a href="{% url 'post_edit' post.pk %}">+ Edit Blog Post</a>
{% endblock content %}
Мы добавили ссылку, используя <a href> ... </a> и тег движка шаблонов Django {% url ...%}.
В нем мы указали целевое имя нашего URL, которое будет называться post_edit, а также
передали необходимый параметр, который является первичным ключом поста post.pk.
Затем мы создаем шаблон для нашей страницы редактирования с именем post_edit.html.
Command Line
(blog) $ touch templates/post_edit.html
И добавьте следующий код:
Группа в ВК "Django_Python"
140
Chapter 6: Forms
Code
<!-- templates/post_edit.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Edit post</h1>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<input type="submit" value="Update" />
</form>
{% endblock %}
Мы снова используем теги HTML <form></form>, csrf_token от Django для безопасности,
form.as_p, чтобы отобразить наши поля формы с тегами абзаца, и, наконец, дать ему
значение “Update” на кнопке отправки.
Теперь к нашему представлению нужно импортировать UpdateView на второй строке с
верху, а затем создать его подкласс в нашем новом представлении BlogUpdateView.
Code
# blog/views.py
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView
from . models import Post
class BlogListView(ListView):
model = Post
template_name = 'home.html'
Группа в ВК "Django_Python"
141
Chapter 6: Forms
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = '__all__'
class BlogUpdateView(UpdateView):
model = Post
fields = ['title', 'body']
template_name = 'post_edit.html'
Обратите внимание, что в представлении BlogUpdateView мы явно перечисляем поля,
которые мы хотим использовать ['title', 'body'], а не " __all__". Это потому, что мы
предполагаем, что автор сообщения не меняется; мы хотим, чтобы только заголовок и
текст были редактируемыми.
Заключительный этап-это обновление вашего файла urls.py как указано:
Группа в ВК "Django_Python"
142
Chapter 6: Forms
Code
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.BlogListView.as_view(), name='home'),
path('post/<int:pk>/', views.BlogDetailView.as_view(), name='post_detail'),
path('post/new/', views.BlogCreateView.as_view(), name='post_new'),
path('post/<int:pk>/edit/',
views.BlogUpdateView.as_view(), name='post_edit'),
]
В верхней части мы добавляем наше представление BlogUpdateView в список
импортированных представлений, затем создали новый шаблон url для /post/pk / edit и
дали ему имя post_edit.
Теперь, если вы нажмете на запись в блоге, вы увидите нашу новую кнопку
редактирования.
Страница блога с кнопкой редактировать
Группа в ВК "Django_Python"
143
Chapter 6: Forms
Если вы нажмете на "+ Edit Blog Pos", вы будете перенаправлены на http://127.0.0.1:8000/post/1/
edit/if это ваш первый пост в блоге.
Страница редактирования
Обратите внимание, что форма предварительно заполняется существующими данными
нашей базы данных для публикации. Давайте внесем изменения…
Группа в ВК "Django_Python"
144
Chapter 6: Forms
Blog edit page
И после нажатия кнопки "Update" мы перенаправляемся в подробный вид поста, где вы
можете увидеть изменения. Это из-за нашей установки get_absolute_url. Перейдите на
главную страницу, и вы увидите изменения рядом со всеми остальными записями.
Группа в ВК "Django_Python"
145
Chapter 6: Forms
Домашняя страница блога с отредактированным сообщением
Удаление View
Процесс создания формы для удаления записей блога очень похож на процесс обновления
записи. Мы будем использовать еще одно общее представление на основе классов,
DeleteView, для создания представления, url-адреса и шаблона функциональности.
Давайте начнем с добавления ссылки для удаления записей блога на Вашей странице
блога,post_-detail.html.
Группа в ВК "Django_Python"
146
Chapter 6: Forms
Code
<!-- templates/post_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="post-entry">
<h2>{{ object.title }}</h2>
<p>{{ object.body }}</p>
</div>
<p><a href="{% url 'post_edit' post.pk %}">+ Edit Blog Post</a></p>
<p><a href="{% url 'post_delete' post.pk %}">+ Delete Blog Post</a></p>
{% endblock content %}
Затем создайте новый файл для нашего шаблона удаления страницы. Сначала выйдите из
локального сервера Control-c, а затем введите следующую команду:
Command Line
(blog) $ touch templates/post_delete.html
И заполните его этим кодом:
Группа в ВК "Django_Python"
147
Chapter 6: Forms
Code
<!-- templates/post_delete.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Delete post</h1>
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ post.title }}"?</p>
<input type="submit" value="Confirm" />
</form>
{% endblock %}
Обратите внимание, что мы используем post.title для отображения заголовка нашего блога.
Мы также могли бы просто использовать object.title, поскольку он также предоставляется
DetailView.
Теперь обновите наш файл views.py, импортировав DeleteView и reverse_lazy вверху, затем
создайте новое представление, которое подкласс DeleteView.
Code
# blog/views.py
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from . models import Post
class BlogListView(ListView):
model = Post
Группа в ВК "Django_Python"
148
Chapter 6: Forms
template_name = 'home.html'
class BlogDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
class BlogCreateView(CreateView):
model = Post
template_name = 'post_new.html'
fields = '__all__'
class BlogUpdateView(UpdateView):
model = Post
fields = ['title', 'body']
template_name = 'post_edit.html'
class BlogDeleteView(DeleteView):
model = Post
template_name = 'post_delete.html'
success_url = reverse_lazy('home')
Мы используем reverse_lazy вместо просто reverse, чтобы он не выполнял перенаправление
URL, пока наше представление не завершило удаление сообщения в блоге.
Наконец, добавьте URL, импортировав наш BlogDeleteView и добавив новый шаблон:
Группа в ВК "Django_Python"
149
Chapter 6: Forms
Code
# blog/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.BlogListView.as_view(), name='home'),
path('post/<int:pk>/', views.BlogDetailView.as_view(), name='post_detail'),
path('post/new/', views.BlogCreateView.as_view(), name='post_new'),
path('post/<int:pk>/edit/',
views.BlogUpdateView.as_view(), name='post_edit'),
path('post/<int:pk>/delete/',
views.BlogDeleteView.as_view(), name='post_delete'),
]
Если вы снова запустите сервер python manage.py runserver и обновите страницу
отдельного сообщения, вы увидите ссылку «Удалить сообщение в блоге».
Группа в ВК "Django_Python"
150
Chapter 6: Forms
Blog delete post
При нажатии на ссылку мы попадаем на страницу удаления записи блога, где отображается
название записи блога.
страница удалить запись
Если вы нажмете на кнопку “Confirm”, то будуте перенаправлены на домашнию страницу,
где пост был удален!
Группа в ВК "Django_Python"
151
Chapter 6: Forms
Домашняя страница с удаленным сообщением
Так это работает!
Tests
Время для тестов, чтобы убедиться, что все работает сейчас–и в будущем-как и ожидалось.
Мы добавили метод get_absolute_url в нашу модель и новые представления для создания,
обновления и редактирования записей. Это означает, что нам нужно четыре новых теста:
• def test_get_absolute_url
• def test_post_create_view
• def test_post_update_view
• def test_post_delete_view
Обновите существующий tests.py файл следующим образом.
Группа в ВК "Django_Python"
152
Chapter 6: Forms
Code
# blog/tests.py
from django.contrib.auth import get_user_model
from django.test import Client, TestCase
from django.urls import reverse
from .models import Post
class BlogTests(TestCase):
def setUp(self):
self.user = get_user_model().objects.create_user(
username='testuser',
email='test@email.com',
password='secret'
)
self.post = Post.objects.create(
title='A good title',
body='Nice body content',
author=self.user,
)
def test_string_representation(self):
post = Post(title='A sample title')
self.assertEqual(str(post), post.title)
Группа в ВК "Django_Python"
153
Chapter 6: Forms
def test_get_absolute_url(self):
self.assertEquals(self.post.get_absolute_url(), '/post/ /')
def test_post_content(self):
self.assertEqual(f'{self.post.title}', 'A good title')
self.assertEqual(f'{self.post.author}', 'testuser')
self.assertEqual(f'{self.post.body}', 'Nice body content')
def test_post_list_view(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code,
)
self.assertContains(response, 'Nice body content')
self.assertTemplateUsed(response, 'home.html')
def test_post_detail_view(self):
response = self.client.get('/post/ /')
no_response = self.client.get('/post/
/')
self.assertEqual(response.status_code,
)
self.assertEqual(no_response.status_code,
)
self.assertContains(response, 'A good title')
self.assertTemplateUsed(response, 'post_detail.html')
def test_post_create_view(self):
response = self.client.post(reverse('post_new'), {
'title': 'New title',
'body': 'New text',
'author': self.user,
})
Группа в ВК "Django_Python"
154
Chapter 6: Forms
self.assertEqual(response.status_code,
)
self.assertContains(response, 'New title')
self.assertContains(response, 'New text')
def test_post_update_view(self):
response = self.client.post(reverse('post_edit', args=' '), {
'title': 'Updated title',
'body': 'Updated text',
})
self.assertEqual(response.status_code,
)
def test_post_delete_view(self):
response = self.client.get(
reverse('post_delete', args=' '))
self.assertEqual(response.status_code,
)
Мы ожидаем, что URL нашего теста будет в post / 1 /, поскольку там только один пост, а 1 его первичный ключ, который Django автоматически добавляет для нас. Чтобы
протестировать создание представления, мы создаем новый ответ и затем проверяем, что
ответ проходит (код состояния 200) и содержит наш новый заголовок и основной текст.
Для просмотра обновлений мы обращаемся к первому сообщению, в котором в качестве
единственного аргумента указан pk, равный 1, и подтверждаем, что оно приводит к
перенаправлению 302. Наконец, мы проверяем наше представление удаления,
подтверждая, что если мы удаляем сообщение, код состояния 200 успех.
Всегда можно добавить больше тестов, но это, по крайней мере, охватывает все наши новые
функциональные возможности.
Группа в ВК "Django_Python"
155
Chapter 6: Forms
Заключение
В небольшом количестве кода мы создали приложение blog которое позволяет создавать,
читать, обновлять и удалять сообщения в блоге. Эта основная функциональность известна
под аббревиатурой CRUD: Create-Read-Update-Delete. Хотя есть несколько способов
достичь этой же функциональности-мы могли бы использовать представления на основе
функций или написать наши собственные представления на основе классов-мы
продемонстрировали, как мало кода требуется в Django, чтобы это произошло.
В следующей главе мы добавим учетные записи пользователей, а также функции входа,
выхода и регистрации.
Группа в ВК "Django_Python"
Глава 7: Учетные Записи Пользователей
На данный момент мы создали работающее приложение блога, которое использует формы,
но нам не хватает основной части большинства веб-приложений: аутентификации
пользователей.Реализация правильной аутентификации пользователя очень сложна; на
этом пути есть много проблем с безопасностью, так что вы действительно не захотите
реализовывать это самостоятельно. К счастью, Django поставляется с мощной встроенной
системой аутентификации пользователей, которую мы можем использовать.Каждый раз,
когда вы создаете новый проект, по умолчанию Django устанавливает приложение auth,
которое предоставляет нам объект User, содержащий:
• username
• password
• email
• first_name
• last_name
Мы будем использовать этот объект User для реализации входа в систему, выхода из
системы и регистрации в нашем приложении блога.
Login
Django предоставляет нам представление по умолчанию для страницы входа через
LoginView. Все, что нам нужно добавить, это urlpattern на уровне проекта для системы
аутентификации, шаблон входа в систему и небольшое обновление нашего файла
settings.py.
Сначала обновите файл urls.py уровня проекта. Мы разместим наши страницы входа и
выхода в accounts/ URL. Это однострочное дополнение в предпоследней строке.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
157
Code
# blog_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('', include('blog.urls')),
]
Как отмечается в документации к LoginView, по умолчанию Django будет искать в папке с
шаблонами, с именем registration , файл с именем login.html для формы входа. Таким
образом, нам нужно создать новый каталог с именем Registration и необходимым файлом
внутри него. В командной строке введите Control-C, чтобы выйти из нашего локального
сервера. Затем введите следующее:
Command Line
(blog) $ mkdir templates/registration
(blog) $ touch templates/registration/login.html
Теперь введите следующий код шаблона для нашего вновь созданного файла.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
158
Code
<!-- templates/registration/login.html -->
{% extends 'base.html' %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Login</button>
</form>
{% endblock content %}
Мы используем HTML теги <form> </ form> и указываем метод POST, так как мы
отправляем данные на сервер (мы будем использовать GET, если запрашиваем данные,
например, в форме поисковой системы). Мы добавляем {% csrf_token%} из соображений
безопасности, а именно для предотвращения атаки XSS. Содержимое формы выводится
между тегами абзаца благодаря {{form.as_p}}, а затем мы добавляем кнопку «submit».На
последнем шаге нам нужно указать, куда перенаправить пользователя при успешном входе
в систему. Мы можем установить это с помощью параметра LOGIN_REDIRECT_URL.
Внизу файла settings.py добавьте следующее:
Code
# settings.py
LOGIN_REDIRECT_URL = 'home'
Теперь пользователь будет перенаправлен на шаблон "home", который является нашей
домашней страницей.
На данный момент мы закончили! Если теперь снова запустить сервер Django с python
manage.py runserver и перейдите на нашу страницу входа:
Группа в ВК "Django_Python"
159
Chapter 7: User Accounts
http://127.0.0.1:8000/accounts/login/
You’ll see the following:
Login page
После ввода регистрационных данных для нашей учетной записи суперпользователя, мы
перенаправлены на главную страницу. Обратите внимание, что мы не добавили никакой
логики представления и не создавали модель базы данных, потому что система Django auth
предоставляется для нас автоматически. Спасибо Джанго!
Обновленние домашней страницы
Давайте обновим наш шаблон base.html, чтобы мы могли отображать сообщение
пользователям независимо от того, вошли они в систему или нет. Мы можем использовать
для этого атрибут is_authenticated.На данный момент мы можем просто разместить этот
код на видном месте. Позже мы можем стилизовать его более подходящим образом.
Обновите файл base.html, добавив новый код, начинающийся с закрывающего тега
</ header>.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
Code
<!-- templates/base.html -->
...
</header>
{% if user.is_authenticated %}
<p>Hi {{ user.username }}!</p>
{% else %}
<p>You are not logged in.</p>
<a href="{% url 'login' %}">login</a>
{% endif %}
{% block content %}
{% endblock content %}
Если пользователь вошел в систему, мы передаем ему привет по имени, если нет, мы
предоставляем ссылку на нашу недавно созданную страницу входа.
Группа в ВК "Django_Python"
160
161
Chapter 7: User Accounts
Homepage logged in
Это сработало! Моего суперпользователя зовут wsv, вот что я вижу на странице.
Ссылка на выход
Мы добавили логику страницы шаблона для пользователей, вышедших из системы, но ...
как нам выйти сейчас? Мы могли бы зайти в панель администратора и сделать это вручную,
но есть и лучший способ. Давайте вместо этого добавим ссылку выхода из системы,
которая перенаправляет на домашнюю страницу. Благодаря системе аутентификации
Django этого достичь очень просто.
В нашем файле base.html добавьте однострочную ссылку {% url 'logout'%} для выхода из
системы.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
162
Command Line
<!-- templates/base.html-->
...
{% if user.is_authenticated %}
<p>Hi {{ user.username }}!</p>
<p><a href="{% url 'logout' %}">logout</a></p>
{% else %}
...
Это все, что нам нужно сделать, так как необходимое представление предоставляется нам
приложением Django auth. Нам нужно указать, куда перенаправить пользователя при
выходе из системы.
Обновите файл settings.py, чтобы предоставить ссылку для перенаправления, которая
соответственно называется LOGOUT_-REDIRECT_URL. Мы можем добавить его прямо
рядом с нашим перенаправлением входа в систему, чтобы нижняя часть файла выглядела
следующим образом:
Code
# blog_project/settings.py
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'
Если вы обновите домашнюю страницу, то увидите, что на ней теперь есть ссылка «Выйти» для
зарегистрированных пользователей.
Группа в ВК "Django_Python"
163
Chapter 7: User Accounts
Homepage logout link
И нажав на нее, вы вернетесь на домашнюю страницу с ссылкой для входа.
Группа в ВК "Django_Python"
164
Chapter 7: User Accounts
Homepage logged out
Попробуйте несколько раз войти в систему и выйти из нее под своей учетной записью.
Регистрация
Нам нужно написать собственное представление для страницы регистрации для
регистрации новых пользователей, но Django предоставляет нам класс формы
UserCreationForm, чтобы упростить задачу. По умолчанию он имеет три поля: имя
пользователя, пароль1, и пароль 2.
Есть много способов организовать ваш код и структуру URL для надежной системы
аутентификации пользователей. Здесь мы создадим новое приложение, accounts, для нашей
страницы регистрации.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
Command Line
(blog) $ python manage.py startapp accounts
Добавьте новое приложение в параметр INSTALLED_APPS в settings.py
файл. Code
# blog_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'blog',
'accounts',
]
Затем добавьте URL уровня проекта, указывающий на это новое приложение, ниже
включаемого встроенного приложения auth .
Группа в ВК "Django_Python"
165
Chapter 7: User Accounts
166
Code
# blog_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('accounts/', include('django.contrib.auth.urls')),
path('accounts/', include('accounts.urls')),
path('', include('blog.urls')),
]
Здесь важен порядок наших URL, потому что Django читает этот файл сверху вниз.
Поэтому, когда мы запрашиваем их /accounts/signup url, Django сначала смотрит в auth, не
находит его, а затем переходит к приложению account.
Давайте продолжим и создадим наш файл account / urls.py.
Command Line
(blog) $ touch accounts/urls.py
И добавьте следующий код:
Группа в ВК "Django_Python"
Chapter 7: User Accounts
167
Code
# acounts/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUpView.as_view(), name='signup'),
]
Мы используем еще не созданное представление с именем RegistrationView, которое, как
мы уже знаем, основано на классе, так как оно написано заглавными буквами и имеет
суффикс as_view (). Его путь просто signup/ поэтому общим путем будет accounts/
signup/.Сейчас представление, которое использует встроенную UserCreationForm и
универсальный CreateView.
Code
# accounts/views.py
from django.contrib.auth.forms import UserCreationForm
from django.urls import reverse_lazy
from django.views import generic
class SignUpView(generic.CreateView):
form_class = UserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
Мы создаем подкласс общего представления на основе классов CreateView в нашем классе
SignUpView. Мы указываем использование встроенного UserCreationForm и еще не
созданного шаблона в signup.html. И мы используем reverse_lazy, чтобы перенаправить
пользователя на страницу входа в систему после успешной регистрации.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
168
Зачем здесь использовать reverse_lazy вместо reverse? Причина в том, что для всех общих
представлений на основе классов URL не загружаются при импорте файла, поэтому мы
должны использовать ленивую форму реверса, чтобы загрузить их позже, когда они станут
доступны.
Теперь давайте добавим signup.html в нашу папку шаблонов уровня проекта:
Command Line
(blog) $ touch templates/signup.html
Добавьте, а затем заполните его кодом ниже.
Code
<!-- templates/signup.html -->
{% extends 'base.html' %}
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
Этот формат очень похож на то, что мы делали раньше. Мы расширяем наш базовый
шаблон сверху, размещаем нашу логику между тегами <form> </ form>, используем
csrf_token для безопасности, отображаем содержимое формы в тегах абзаца с помощью
form.as_p и добавляем кнопку отправки.
Группа в ВК "Django_Python"
169
Chapter 7: User Accounts
Теперь мы закончили! Чтобы проверить это, перейдите на нашу новую
страницу: http://127.0.0.1:8000/accounts/signup/
Django signup page
Обратите внимание, что по умолчанию в Django есть много лишнего текста. Мы можем
настроить это, используя что-то вроде встроенной платформы сообщений, но пока
попробуйте форму.
Я создал нового пользователя с именем «william» и после отправки был перенаправлен на
страницу входа. Затем, после успешного входа в систему с использованием моего нового
пользователя и пароля, я был перенаправлен на домашнюю страницу с нашим
персонализированным приветствием «Привет, имя пользователя».
Группа в ВК "Django_Python"
170
Chapter 7: User Accounts
Homepage for user wsvincent
Таким образом, наш конечный поток: Signup -> Login -> Homepage. И, конечно, мы можем
настроить это, как мы хотим. RegistrationView перенаправляет на вход в систему, потому
что мы установили success_url = reverse_lazy ('login'). Страница входа перенаправляется на
домашнюю
страницу,
потому
что
в
нашем
файле
settings.py
мы
установили
LOGIN_REDIRECT_URL = 'home'.
На первый взгляд может показаться сложным отслеживать все различные части проекта
Django. Это нормально. Но я обещаю, что со временем они станут более понятными.
Bitbucket
Прошло много времени с тех пор, как мы сделали git commit. Давайте сделаем это, а затем
вставим копию нашего кода в Bitbucket.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
171
Сначала проверьте всю новую работу, которую мы сделали с git status.
Command Line
(blog) $ git status
Затем добавьте новый контент.
Command Line
(blog) $ git commit -m 'forms and user accounts'
Создайте новый репозиторий на Bitbucket, который вы можете назвать как угодно. Я
выберу название blog-app. Поэтому после создания нового репо на сайте Bitbucket я могу
ввести следующие две команды. Обязательно замените мое имя пользователя wsvincent
вашим именем пользователя из Bitbucket.
Command Line
(blog) $ git remote add origin git@bitbucket.org:wsvincent/blog-app.git
(blog) $ git push -u origin master
Все сделано! Теперь мы можем развернуть наше новое приложение на Heroku.
Heroku конфигурация
Это наше третье развертывание приложения. Как и в нашем приложении Message Board
(доска сообщений), есть четыре изменения, которые нам нужно сделать, чтобы его можно
было развернуть на Heroku.
• обновить Pipfile.lock
• новый Procfile
• установить gunicorn
Группа в ВК "Django_Python"
Chapter 7: User Accounts
172
• обновить settings.py
Мы укажем версию Python в нашем Pipfile, а затем запустим pipenv, чтобы применить ее к
Pipfile.lock. Мы добавим Procfile, который является файлом конфигурации, специфичным
для Heroku, установим gunicorn для запуска в качестве нашего рабочего веб-сервера вместо
локального сервера Django и, наконец, обновим ALLOWED_HOSTS, чтобы любой мог
просматривать наше приложение.
Откройте Pipfile в текстовом редакторе и в нижней части добавьте следующие две строки.
Code
# Pipfile
[requires]
python_version = " . "
Мы используем здесь «3.6», А не более конкретный «3.6.4», так что наше приложение
автоматически обновляется до самой последней версии Python 3.6x для Heroku.Теперь
запустите pipenv lock, чтобы обновить наш Pipfile.lock, поскольку Heroku будет
использовать его для создания новой среды на серверах Heroku для нашего приложения.
Command Line
(blog) $ pipenv lock
Создайте новый файл Procfile .
Command Line
(blog) $ touch Procfile
В вашем текстовом редакторе добавьте следующую строку в Procfile. Это говорит Heroku
использовать gunicorn, а не локальный сервер, который не подходит для производства.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
173
Code
web: gunicorn blog_project.wsgi --log-file -
Сейчас установите gunicorn.
Command Line
(blog) $ pipenv install gunicorn
Наконец, обновите ALLOWED_HOSTS, чтобы принять все домены, которые представлены
звездочкой *.
Code
# blog_project/settings.py
ALLOWED_HOSTS = ['*']
Мы можем зафиксировать(commit) наши новые изменения и отправить их в Bitbucket.
Command Line
(blog) $ git status
(blog) $ git add -A
(blog) $ git commit -m 'Heroku config files and updates'
(blog) $ git push -u origin master
Развертывание на Heroku
Для развертывания в Heroku сначала убедитесь, что вы вошли в свою существующую
учетную запись Heroku.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
174
Command Line
(blog) $ heroku login
Затем выполните команду create, которая скажет Heroku создать новый контейнер для
нашего приложения. Если вы просто запустите heroku create, Heroku назначит вам
произвольное имя, однако вы можете указать произвольное имя, но оно должно быть
уникальным в Heroku. Другими словами, так как я выбираю название dfb-blog, вы не
сможете дать такое же имя. Вам нужна другая комбинация букв и цифр.
Command Line
(blog) $ heroku create dfb-blog
Теперь настройте git таким образом, чтобы при переходе на Heroku он переходил к новому
имени приложения (заменив dfb-blog своим произвольным именем).
Command Line
(blog) $ heroku git:remote -a dfb-blog
Теперь мы должны сделать еще один шаг, когда у нас есть статические файлы, в нашем
случае это CSS. Django не поддерживает обслуживание статических файлов в производстве,
однако проект WhiteNoise поддерживает. Итак, давайте установим его.
Command Line
(blog) $ pipenv install whitenoise
Затем нам нужно обновить наши static настройки, чтобы они были использованы в
производстве. В вашем текстовом редакторе откройте settings.py. Добавьте whitenoise в
INSTALLED_APPS над встроенным приложением staticfiles, а также в MIDDLEWARE в
третьей строке. Порядок имеет значение как для INSTALLED_APPS, так и для
MIDDLEWARE.
Внизу файла добавьте новые строки для STATIC_ROOT и STATICFILES_STORAGE. Это
должно выглядеть следующим образом.
Группа в ВК "Django_Python"
Chapter 7: User Accounts
Code
# blog_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'whitenoise.runserver_nostatic', # new!
'django.contrib.staticfiles',
'blog',
'accounts',
]
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'whitenoise.middleware.WhiteNoiseMiddleware', # new!
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
...
STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles') # new!
Группа в ВК "Django_Python"
175
176
Chapter 7: User Accounts
STATIC_URL = '/static/'
STATICFILES_DIRS = [os.path.join(BASE_DIR, 'static')]
STATICFILES_STORAGE = 'whitenoise.storage.CompressedManifestStaticFilesStorage' \
# new!
Не забудьте добавить и зафиксировать новые изменения. Затем нажмите на Bitbucket.
Command Line
(blog) $ git add -A
(blog) $ git commit -m 'Heroku config'
(blog) $ git push origin master
Наконец, мы можем перенести наш код в Heroku и добавить веб-процесс, чтобы dyno работал.
Command Line
(blog) $ git push heroku master
(blog) $ heroku ps:scale web=
URL вашего нового приложения будет в выходных данных командной строки, или вы
можете запустить heroku open, чтобы найти его. Мой находится по адресу https://df bblog.herokuapp.com/.
Heroku site
Группа в ВК "Django_Python"
Chapter 7: User Accounts
177
Заключение
С минимальным количеством кода, фреймворк Django позволил нам создать поток
аутентификации пользователя для входа в систему, выхода из системы и регистрации. Он
позаботился о многих проблемах безопасности, которые могут возникнуть, если вы
попытаетесь создать собственный поток аутентификации пользователя с нуля.
Группа в ВК "Django_Python"
Глава 8: Custom User Model
Встроенная в Django модель User позволяет нам сразу начать работать с пользователями,
как мы только что делали с нашим приложением блога в предыдущих главах. Однако
официальная
документация
Django
настоятельно
рекомендует
использовать
пользовательскую модель для новых проектов. Причина в том, что если вы хотите внести
какие-либо изменения в пользовательскую модель в будущем например, добавив поле
возраста с помощью custom user model с самого начала это довольно просто. Но если вы не
создадите custom user model, обновление модели пользователя по умолчанию в
существующем проекте Django будет очень и очень сложным.
Поэтому всегда используйте пользовательскую модель для всех новых проектов Django.
Однако пример официальной документации не совсем то, что рекомендуют многие
эксперты Django. Он использует довольно сложный AbstractBaseUser, чем если мы просто
используем AbstractUser, все гораздо проще и все еще настраиваемо. Это подход, который
мы будем использовать в этой главе, где мы правильно запускаем новое приложение
Newspaper(Газета) с пользовательской моделью. Выбор приложения газеты отдает дань
уважения корням Django в качестве веб фреймворка, созданного для редакторов и
журналистов в Lawrence Journal-World.
Настройка
Первым шагом является создание нового проекта Django из командной строки. Нам нужно
сделать несколько вещей:
• создать и перейти в новый каталог для нашего кода
• создать новую виртуальную среду news
• установка Django
• создать новый проект Django newspaper_project
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
179
• сделать новое приложение users
Мы называем наше приложение для управления пользователями users, но вы также
увидите его часто называемыми учетными записями в открытом исходном коде.
Фактическое имя не имеет значения, если вы последовательны в обращении к нему на
протяжении всего проекта.
Вот команды для запуска:
Command Line
$ cd ~/Desktop
$ mkdir news
$ cd news
$ pipenv install django
$ pipenv shell
(news) $ django-admin startproject newspaper_project .
(news) $ python manage.py startapp users
(news) $ python manage.py runserver
Обратите внимание, что мы не выполняли миграцию для настройки базы данных. Важно
подождать, пока мы не создадим нашу новую пользовательскую модель, прежде чем делать
это, учитывая, насколько тесно связана пользовательская модель с остальной частью
Django.
Если вы перейдете к http://127.0.0.1:8000 вы увидите знакомый экран приветствия Django.
Группа в ВК "Django_Python"
180
Chapter 8: Custom User Model
Welcome page
Custom User Model
Создание нашей собственной модели пользователя
требует четыре шага:
• обновить settings.py
• создание новой CustomUser модели
• создание новой формы для UserCreation и
UserChangeForm
• обновить админку сайта
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
181
В settings.py мы добавим приложение users в наш INSTALLED_APPS. Затем в нижней части
файла используйте конфигурацию AUTH_USER_MODEL, чтобы указать Django
использовать нашу новую пользовательскую модель вместо встроенной модели User. Мы
будем называть нашу пользовательскую пользовательскую модель CustomUser так,
поскольку она существует в нашем users приложении, мы называем ее users.CustomUser.
Code
# newspaper_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users', # new
]
...
AUTH_USER_MODEL = 'users.CustomUser'
Теперь обновите users / models.py новой моделью User, которую мы будем называть
CustomUser. Мы также добавим наше первое дополнительное поле для «age»(возраста)
наших пользователей. Мы можем использовать PositiveIntegerField от Django, что означает,
что целое число должно быть либо положительным, либо нулевым.
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
182
Code
# users/models.py
from django.contrib.auth.models import AbstractUser
from django.db import models
class CustomUser(AbstractUser):
age = models.PositiveIntegerField(default= )
Это действительно весь код, который нам нужен! Поскольку мы расширяем AbstractUser,
наш CustomUser является в основном копией модели User по умолчанию. Единственное
обновление - наше поле age.
Формы
Если мы на шаг отступим назад, как мы будем взаимодействовать с нашей новой моделью
CustomUser? Первый случай, когда пользователь регистрирует новую учетную запись на
нашем сайте. Другой находится в приложении администратора, которое позволяет нам, как
суперпользователям, изменять существующих пользователей. Поэтому нам нужно
обновить две встроенные формы для этой функции: UserCreationForm и UserChangeForm.
Остановите локальный сервер с помощью Control + c и создайте новый файл в приложении
users с именем forms.py.
Command Line
(news) $ touch users/forms.py
Мы обновим его следующим кодом, чтобы расширить существующие формы
UserCreationForm и UserChangeForm.
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
183
Code
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
Для обеих новых форм мы устанавливаем модель CustomUser и используем поля по
умолчанию с помощью Meta.fields.
TПоначалу понятие полей в форме может сбивать с толку, поэтому давайте уделим
немного времени, чтобы изучить его дальше. Наша модель CustomUser содержит все поля
модели пользователя по умолчанию и наше дополнительное поле возраста, которое мы
установили. Но что это за поля по умолчанию? Оказывается, есть много, включая имя
пользователя, имя, фамилия, адрес электронной почты, пароль, группы и многое другое.
Тем не менее, когда пользователь регистрирует новую учетную запись в Django, форма по
умолчанию запрашивает только имя пользователя, адрес электронной почты и пароль.
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
184
Это говорит нам о том, что настройка по умолчанию для полей в UserCreationForm - это
просто имя пользователя, адрес электронной почты и пароль, хотя доступно еще много
полей. Это может быть не понятно, так как для правильного понимания форм и моделей
требуется некоторое время. В следующей главе мы создадим наши собственные страницы
регистрации, входа и выхода, которые будут более четко связывать нашу модель
CustomUser и формы. Так что держитесь! Последний шаг это обновить наш файл admin.py,
так как Admin тесно связан с моделью пользователя по умолчанию. Мы расширим
существующий класс UserAdmin для использования нашей новой модели CustomUser и
двух новых форм.
Code
# users/admin.py
from django.contrib import admin
from django.contrib.auth.admin import UserAdmin
from .forms import CustomUserCreationForm, CustomUserChangeForm
from .models import CustomUser
class CustomUserAdmin(UserAdmin):
add_form = CustomUserCreationForm
form = CustomUserChangeForm
list_display = ['email', 'username', 'age']
model = CustomUser
admin.site.register(CustomUser, CustomUserAdmin)
Обратите внимание, что наш CustomUserAdmin также имеет параметр list_display, чтобы
он отображал только поля email, username и age, даже если на данный момент в модели
CustomUser их гораздо больше.
Группа в ВК "Django_Python"
Chapter 8: Custom User Model
185
Хорошо, мы закончили! Запустите makemigrations и выполните миграцию в первый раз,
чтобы создать новую базу данных, использующую пользовательскую модель.
Command Line
(news) $ python manage.py makemigrations
(news) $ python manage.py migrate
Superuser
Давайте создадим учетную запись суперпользователя, чтобы подтвердить, что все
работает, как ожидалось. В командной строке введите следующую команду и выполните
запросы.
Command Line
(news) $ python manage.py createsuperuser
Тот факт, что это работает, является первым доказательством того, что наша
пользовательская модель работает, как и ожидалось. Давайте посмотрим на админку,
чтобы быть более уверенным.
Запустите веб-сервер.
Command Line
(news) $ python manage.py runserver
Затем перейдите в админку по адресу http://127.0.0.1:8000/admin и войдите в систему.
Группа в ВК "Django_Python"
186
Chapter 8: Custom User Model
Admin page
Если вы нажмете на ссылку "Users", вы увидите свою учетную запись суперпользователя.
Обратите внимание, что три поля, которые мы видим, электронная почта, имя
пользователя и возраст, так как мы установили, как list_-display в нашем CustomUserAdmin.
Группа в ВК "Django_Python"
187
Chapter 8: Custom User Model
Admin one user
Заключение
Теперь, когда наша пользовательская модель готова, мы можем сосредоточиться на
создании остальной части нашего приложения Newspaper . В следующей главе мы
настроим страницы регистрации, входа и выхода.
Группа в ВК "Django_Python"
Глава 9: Аутентификация пользователя
Теперь, когда у нас есть рабочая пользовательская модель, мы можем добавить
функциональность, которая нужна каждому веб-сайту: возможность регистрироваться,
входить и выходить из системы. Django предоставляет все необходимое для входа и выхода,
но нам нужно будет создать собственную форму для регистрации новых пользователей. Мы
также создадим базовую домашнюю страницу со ссылками на все три функции, поэтому
нам не придется каждый раз вводить URL вручную.
Templates(Шаблоны)
По умолчанию загрузчик шаблонов Django ищет шаблоны в вложенной структуре в
каждом приложении. Таким образом, шаблон home.html для пользователей должен быть
расположен по адресу users / templates / users / home.html. Но подход к папке с шаблонами
на уровне проекта более понятен и лучше масштабируется, поэтому мы будем использовать
его.Давайте создадим новый каталог шаблонов и внутри него папку registration, в которой
Django будет искать шаблон login.
Command Line
(news) $ mkdir templates
(news) $ mkdir templates/registration
Теперь нам нужно сообщить Django об этом новом каталоге, обновив конфигурацию для
'DIRS' в settings.py. Это изменение в одну строку.
Группа в ВК "Django_Python"
Chapter 9: User Authentication
189
Code
# newspaper_project/settings.py
TEMPLATES = [
{
...
'DIRS': [os.path.join(BASE_DIR, 'templates')],
...
}
]
Если вы думаете о том, что происходит, когда вы входите или выходите из сайта, вы сразу
же перенаправляетесь на следующую страницу. Нам нужно указать Django, куда отправлять
пользователей в каждом конкретном случае. Делают это настройки
LOGIN_REDIRECT_URL и LOGOUT_REDIRECT_URL. Мы настроим оба, чтобы
перенаправить на нашу домашнюю страницу, которая будет иметь названный URL
«home».Помните, что когда мы создаем наши маршруты URL, у нас есть возможность
добавить имя для каждого из них. Поэтому, когда мы создадим URL домашней страницы,
мы обязательно назовем его «home».Добавьте эти две строки внизу файла settings.py.
Code
# newspaper_project/settings.py
LOGIN_REDIRECT_URL = 'home'
LOGOUT_REDIRECT_URL = 'home'
Now we can create four new templates:
Группа в ВК "Django_Python"
Chapter 9: User Authentication
190
Command Line
(news) $ touch templates/registration/login.html
(news) $ touch templates/base.html
(news) $ touch templates/home.html
(news) $ touch templates/signup.html
Вот HTML код для каждого используемого файла. base.html будет унаследован каждым
другим шаблоном в нашем проекте. Используя блок типа {% block content %}, мы можем
позже переопределить содержимое только в этом месте в других шаблонах.
Code
<!-- templates/base.html -->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf- ">
<title>Newspaper App</title>
</head>
<body>
<main>
{% block content %}
{% endblock %}
</main>
</body>
</html>
Группа в ВК "Django_Python"
Chapter 9: User Authentication
Code
<!-- templates/home.html -->
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
{% if user.is_authenticated %}
Hi {{ user.username }}!
<p><a href="{% url 'logout' %}">logout</a></p>
{% else %}
<p>You are not logged in</p>
<a href="{% url 'login' %}">login</a> |
<a href="{% url 'signup' %}">signup</a>
{% endif %}
{% endblock %}
Code
<!-- templates/registration/login.html -->
{% extends 'base.html' %}
{% block title %}Login{% endblock %}
{% block content %}
<h2>Login</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
Группа в ВК "Django_Python"
191
Chapter 9: User Authentication
192
<button type="submit">Login</button>
</form>
{% endblock %}
Code
<!-- templates/signup.html -->
{% extends 'base.html' %}
{% block title %}Sign Up{% endblock %}
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form.as_p }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
Наши шаблоны готовы. Тем не менее перейдем к нашим URL и представлениям.
URLs
Давайте начнем с URL-маршрутов. В нашем файле urls.py уровня проекта мы хотим, чтобы
наш шаблон home.html отображался в качестве домашней страницы. Но мы пока не хотим
создавать приложение для выделенных страниц, поэтому мы можем использовать быстрый
доступ импортируя TemplateView и установки имени шаблона прямо в нашем шаблоне
URL.
Группа в ВК "Django_Python"
Chapter 9: User Authentication
193
Далее мы хотим «включить» и приложение пользователя, и встроенное приложение
аутентификации. Причина в том, что встроенное приложение авторизации уже
предоставляет представления и URL для входа и выхода из системы. Но для регистрации
нам нужно создать наш собственное представление и URL. Чтобы обеспечить
согласованность наших URL маршрутов, мы размещаем в users/, поэтому возможными URL
будут / users / login, / users / logout и / users / signup.
Code
# newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include
from django.views.generic.base import TemplateView
urlpatterns = [
path('', TemplateView.as_view(template_name='home.html'), name='home'),
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
]
Создайте файл urls.py в приложении users.
Command Line
(news) $ touch users/urls.py
Обновите users / urls.py следующим кодом:
Группа в ВК "Django_Python"
Chapter 9: User Authentication
194
Code
# users/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('signup/', views.SignUp.as_view(), name='signup'),
]
Последний шаг это наш файл views.py, который будет содержать логику для нашей формы
регистрации. Здесь мы используем общий CreateView от Django и говорим ему
использовать нашу CustomUserCreation-Form и перенаправлять на вход в систему после
успешной регистрации пользователя, и что наш шаблон называется signup.html.
Code
# users/views.py
from django.urls import reverse_lazy
from django.views import generic
from .forms import CustomUserCreationForm
class SignUp(generic.CreateView):
form_class = CustomUserCreationForm
success_url = reverse_lazy('login')
template_name = 'signup.html'
Отлично! Мы это сделали. Давайте все проверим.Запустите сервер с помощью python
manage.py runserver и перейдите на домашнюю страницу по адресу http://127.0.0.1:8000/.
Группа в ВК "Django_Python"
195
Chapter 9: User Authentication
Homepage logged in
Мы вошли в систему администратора в предыдущей главе, поэтому вы должны увидеть
персональное приветствие. Нажмите на ссылку выхода.
Homepage logged out
Теперь мы на главной странице. Идем вперед и нажимаем на ссылку входа в систему и
используем свои учетные данные суперпользователя.
Login
После успешного входа в систему вы будете перенаправлены обратно на главную страницу
и увидите то же персонализированное приветствие. Работает!
Группа в ВК "Django_Python"
196
Chapter 9: User Authentication
Homepage logged in
Теперь используйте ссылку выхода, чтобы вернуться на главную страницу, и на этот раз
нажмите на ссылку регистрации.
Homepage logged out
Вы будете перенаправлены на страницу регистрации(signup ).
Signup page
Создайте нового пользователя. Мой называется testuser. После успешной отправки формы
вы будете перенаправлены на страницу входа(login ). Войдите в систему с новым
пользователем, и вы снова будете
Группа в ВК "Django_Python"
197
Chapter 9: User Authentication
перенаправлены на домашнюю страницу с персонализированным приветствием для нового
пользователя.
Homepage for testuser
Все работает, как и ожидалось.
Admin
Давайте также войдем в admin для просмотра наших двух учетных записей
пользователей. Перейдите к: http://127.0.0.1:8000/admin и …
Группа в ВК "Django_Python"
198
Chapter 9: User Authentication
Admin login wrong
Что это такое? Почему мы не можем войти?
Потому что мы вошли в систему с нашей новой учетной записью тестового пользователя, а
не с учетной записью суперпользователя. Только учетная запись суперпользователя имеет
разрешения для входа в систему администратора! Поэтому используйте свою учетную
запись суперпользователя для входа.
После этого вы увидите обычную домашнюю страницу администратора. Нажмите на Users
и вы увидите наших двух пользователей: того, которого мы только что создали, и ваше
предыдущее имя суперпользователя (мое-wsv).
Группа в ВК "Django_Python"
199
Chapter 9: User Authentication
Users in the Admin
Все работает, но вы можете заметить, что для нашего тестового пользователя нет поля
электронной почты. Почему так? Ну, оглянитесь на страницу регистрации в users/signup/, и
вы увидите, что она запрашивает только имя пользователя и пароль, а не электронную
почту! Именно так работает настройка Django по умолчанию. Однако мы можем легко
изменить это. Вернемся к нашему файлу users/forms.py.
Сейчас это выглядит так:
Группа в ВК "Django_Python"
Chapter 9: User Authentication
200
Code
# users/forms.py
from django import forms
from django.contrib.auth.forms import UserCreationForm, UserChangeForm
from .models import CustomUser
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = UserCreationForm.Meta.fields
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = UserChangeForm.Meta.fields
Мы используем Meta.поля, которые просто отображают настройки по умолчанию имя
пользователя/пароль. Но мы также можем явно установить, какие поля мы хотим
отобразить, поэтому давайте обновим его, чтобы запросить имя пользователя/адрес
электронной почты/пароль, установив его в ('username', 'email',). Нам не нужно включать поле
пароля, потому что оно необходимо! Но все остальные поля могут быть настроены, как мы
выберем.
Группа в ВК "Django_Python"
Chapter 9: User Authentication
Code
# users/forms.py
...
class CustomUserCreationForm(UserCreationForm):
class Meta(UserCreationForm.Meta):
model = CustomUser
fields = ('username', 'email', ) # new
class CustomUserChangeForm(UserChangeForm):
class Meta:
model = CustomUser
fields = ('username', 'email', ) # new
Теперь, если вы попробуете страницу регистрации снова на http://127.0.0.1:8000/users/
signup/ вы можете увидеть дополнительное поле “Email address”.
Группа в ВК "Django_Python"
201
202
Chapter 9: User Authentication
New sign up page
Зарегистрируйтесь с новой учетной записью пользователя. Я назвал свою testuser2 с
адресом электронной почты testuser2@email.com. Если мы затем переключимся обратно на
страницу администратора и войдем с помощью учетной записи суперпользователя, мы
обнаружим теперь три пользователя.
Группа в ВК "Django_Python"
203
Chapter 9: User Authentication
Three users in the Admin
Аутентификации пользователя Django требует немного настройки, но вы должны начать
видеть, что он также предоставляет нам невероятную гибкость для настройки регистрации
и входа в систему именно так, как мы хотим.
Заключение
До сих пор наше приложение Newspaper имеет кастомную модель пользователя и рабочие
страницы регистрации, входа и выхода. Но вы, возможно, заметили, что наш сайт выглядит
не очень хорошо. В следующей главе мы добавим Bootstrap для стилизации и создадим
приложение Pages.
Группа в ВК "Django_Python"
Глава ��: Bootstrap
Веб-разработка требует много навыков. Вам нужно не только программировать сайт для
корректной работы, но так же пользователи ожидают, что он будет хорошо выглядеть.
Когда вы создаете все с нуля, может быть крайне тяжело добавить все необходимые
HTML / CSS для красивого сайта.
К счастью, есть Bootstrap, самая популярная платформа для создания адаптивных проектов,
ориентированных на мобильные устройства. Вместо того, чтобы писать все наши
собственные CSS и JavaScript для общих функций макета веб-сайта, мы можем вместо этого
положиться на Bootstrap, чтобы сделать тяжелую работу. Это означает, что с небольшим
количеством кода с нашей стороны мы сможем быстро создать великолепно выглядящие
сайты. И если мы хотим вносить изменения по мере развития проекта, то при
необходимости Bootstrap легко переопределить.
Если вы хотите сосредоточиться на функциональности проекта, а не на дизайне, Bootstrap отличный выбор. Вот почему мы будем использовать его здесь.
Приложение Pages
В предыдущей главе мы отображали нашу домашнюю страницу, включив логику просмотра
в наш файл urls.py. Хотя этот подход работает, он кажется мне несколько хакерским, и,
конечно, он не масштабируется, поскольку веб-сайт со временем растет. Это также,
вероятно, несколько сбивает с толку новичков в Django. Вместо этого мы можем и должны
создать специальное приложение для всех наших статических страниц. Это сделает наш код
красивым и организованным далее. В командной строке используйте команду startapp для
создания нашего нового приложения pages. Если сервер все еще работает, вам может
потребоваться сначала нажать Control + c, чтобы выйти из него.
Группа в ВК "Django_Python"
205
Chapter 10: Bootstrap
Command Line
(news) $ python manage.py startapp pages
Затем сразу обновите наш файл settings.py. Я часто забываю делать это, поэтому
рекомендуется думать о создании нового приложения как о двухэтапном процессе:
запустите команду startapp, а затем обновите INSTALLED_APPS.
Code
# newspaper_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'users',
'pages', # new
]
Теперь мы можем обновить наш файл urls.py на уровне проекта. Идем дальше и удалим
импорт TemplateView. Мы также обновим маршрут ' ', чтобы включить приложение pages.
Группа в ВК "Django_Python"
206
Chapter 10: Bootstrap
Code
# newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('', include('pages.urls')),
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
]
Пришло время добавить нашу домашнюю страницу, что означает стандартные urls/views/
templates. Начнем с файла pages/urls.py . Сначала создайте его.
Command Line
(news) $ touch pages/urls.py
Затем импортируйте наши еще не созданные представления, задайте пути маршрута и
убедитесь, что каждый url так же имеет имя(name).
Группа в ВК "Django_Python"
207
Chapter 10: Bootstrap
Code
# pages/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.HomePageView.as_view(), name='home'),
]
На данном этапе код views.py должен выглядеть знакомым. Мы используем представление
шаблонов на основе классов Django, что означает, что нам нужно только указать
template_name, чтобы использовать его.
Code
# pages/views.py
from django.views.generic import TemplateView
class HomePageView(TemplateView):
template_name = 'home.html'
У нас уже есть существующий шаблон home.html . Давайте проверим, что он по прежнему
работает должным образом с нашим новым url и представлением. Перейдите к странице
http://127.0.0.1:8000/ что бы проверить что все остается неизменным.
Группа в ВК "Django_Python"
208
Chapter 10: Bootstrap
Homepage logged in
Он должен показывать имя вашей учетной записи суперпользователя, которую мы
использовали в конце последней главы.
Тесты
Мы добавили новый код и функциональность, что означает, что пришло время для тестов.
Вы никогда не сможете иметь достаточно тестов в своих проектах. Даже если они заранее
время, чтобы написать, они всегда экономят время и дают уверенность по мере
возрастания сложности проекта.
Есть два идеальных момента для добавления тестов: либо перед тем, как писать какой-либо
код (разработка на основе тестов), либо сразу после того, как вы добавили новую
функциональность, и вам должно это быть понятно.
Сейчас наш проект имеет четыре страницы:
• home
• signup
• login
• logout
Однако нам нужно только проверить первые два. Вход и выход из системы являются
частью Django и зависят от внутренних представлений и url маршрутов. Поэтому они уже
имеют тестовое покрытие. Если мы внесем существенные изменения в них в будущем, то
мы захотели бы добавить тесты и для этого. Но, как правило, вам не нужно добавлять тесты
для основной функциональности Django.
Группа в ВК "Django_Python"
209
Chapter 10: Bootstrap
Поскольку у нас есть URL, шаблоны и представления для каждой из наших двух новых
страниц, мы добавим тесты для каждой. SimpleTestCase будет достаточно для тестирования
домашней страницы, но страница регистрации использует базу данных, поэтому нам также
нужно использовать TestCase.
Вот как должен выглядеть код в вашем файле pages/tests.py.
Code
# pages/tests.py
from django.contrib.auth import get_user_model
from django.test import SimpleTestCase, TestCase
from django.urls import reverse
class HomePageTests(SimpleTestCase):
def test_home_page_status_code(self):
response = self.client.get('/')
self.assertEqual(response.status_code,
)
def test_view_url_by_name(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code,
)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('home'))
self.assertEqual(response.status_code,
)
self.assertTemplateUsed(response, 'home.html')
class SignupPageTests(TestCase):
Группа в ВК "Django_Python"
210
Chapter 10: Bootstrap
username = 'newuser'
email = 'newuser@email.com'
def test_signup_page_status_code(self):
response = self.client.get('/users/signup/')
self.assertEqual(response.status_code,
)
def test_view_url_by_name(self):
response = self.client.get(reverse('signup'))
self.assertEqual(response.status_code,
)
def test_view_uses_correct_template(self):
response = self.client.get(reverse('signup'))
self.assertEqual(response.status_code,
)
self.assertTemplateUsed(response, 'signup.html')
def test_signup_form(self):
new_user = get_user_model().objects.create_user(
self.username, self.email)
self.assertEqual(get_user_model().objects.all().count(),
)
self.assertEqual(get_user_model().objects.all()
[ ].username, self.username)
self.assertEqual(get_user_model().objects.all()
[ ].email, self.email)
В верхней строке мы используем get_user_model() для ссылки на нашу пользовательскую
модель. Затем для обеих страниц мы тестируем три вещи:
Группа в ВК "Django_Python"
211
Chapter 10: Bootstrap
• страница существует и возвращает код состояния HTTP 200
• страница использует правильное имя URL в представлении
• используется правильный шаблон
Наша страница регистрации также имеет форму, поэтому мы должны проверить и это. В
тестовой форме test_sign up_ мы проверяем, что когда имя пользователя и адрес
электронной почты публикуются (отправляются в базу данных), они соответствуют тому,
что хранится в модели CustomUser.
Выйдите из локального сервера с Control+c, а затем запустите наши тесты, чтобы
подтвердить, что все проходит.
Command Line
(news) $ python manage.py test
Bootstrap
Если вы никогда не использовали Bootstrap, вы получите реальное удовольствие от его
использования. Он так много делает в таком маленьком коде.
Существует два способа добавить Bootstrap в проект: можно загрузить все файлы и
обслуживать их локально или использовать Сеть Доставки Контента (CDN). Второй
подход проще реализовать, если у вас есть стабильное подключение к интернету, это мы и
будем использовать здесь.
Bootstrap поставляется со стартовым шаблоном, который включает в себя основные
необходимые файлы. В частности, есть четыре, которые мы подключаем:
• Bootstrap.css
• jQuery.js
• Popper.js
• Bootstrap.js
Группа в ВК "Django_Python"
212
Chapter 10: Bootstrap
Вот как должен выглядеть обновленный файл base.html. Как правило, вы должны набирать
все примеры кода самостоятельно, но так как это довольно длинный код, здесь его можно
скопировать и вставить.
Code
<!-- templates/base.html -->
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf- ">
<meta name="viewport" content="width=device-width, initial-scale= , shrink-t\
o-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/ . . \
/css/bootstrap.min.css" integrity="sha
-Gn
xqQ aoWXA+
RXPxPg fy IWvTNh E \
XmFcJlSAwiGgFAW/dAiS JXm" crossorigin="anonymous">
<title>Hello, world!</title>
</head>
<body>
<h1>Hello, world!</h1>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery- . . .slim.min.js" integrity="sh\
a
-KJ o DKtIkvYIK UENzmM KCkRr/rE /Qpg aAZGJwFDMVNA/GpGFF
hXpG KkN" crossorig\
in="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/ .
Группа в ВК "Django_Python"
. /umd/pop\
213
Chapter 10: Bootstrap
per.min.js" integrity="sha
-ApNbgh B+Y QKtv Rn W mgPxhU K/ScQsAP hUibX
j fakF\
PskvXusvfa b Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/ . . /js/bootstrap.mi\
n.js" integrity="sha
-JZR Spejh U
d jOt vLEHfe/JQGiRRSQQxSfFWpi MquVdAyjUar +\
PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
Если вы снова запустите сервер с помощью python manage.py runserver и обновите домашнюю
страницу по адресу http://127.0.0.1:8000/, вы увидите, что в данный момент изменился
только размер шрифта.
Давайте добавим панель навигации вверху страницы, которая содержит наши ссылки для
домашней страницы, входа в систему, выхода из системы и регистрации. В частности, мы
можем использовать теги if / else в шаблонизаторе Django для добавления некоторой
базовой
логики.
Мы
хотим
показать
кнопки
«войти»
и
«зарегистрироваться»
пользователям, которые вышли из системы, а кнопки «выйти» и «изменить пароль»
пользователям, которые вошли в систему.
Вот как выглядит код. Опять же, здесь можно копировать / вставлять, поскольку эта книга
посвящена изучению Django, а не HTML, CSS и Bootstrap.
Code
<!-- templates/base.html -->
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf- ">
<meta name="viewport" content="width=device-width, initial-scale= , shrink-t\
o-fit=no">
Группа в ВК "Django_Python"
214
Chapter 10: Bootstrap
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/ . . \
/css/bootstrap.min.css" integrity="sha
-Gn
xqQ aoWXA+
RXPxPg fy IWvTNh E \
XmFcJlSAwiGgFAW/dAiS JXm" crossorigin="anonymous">
<title>{% block title %}Newspaper App{% endblock title %}</title>
</head>
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb- ">
<a class="navbar-brand" href="{% url 'home' %}">Newspaper</a>
<button class="navbar-toggler" type="button" data-toggle="collapse" data-t\
arget="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" ari\
a-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
<div class="collapse navbar-collapse" id="navbarCollapse">
{% if user.is_authenticated %}
<ul class="navbar-nav ml-auto">
<li class="nav-item">
<a class="nav-link dropdown-toggle" href="#" id="userMenu" data-to\
ggle="dropdown" aria-haspopup="true" aria-expanded="false">
{{ user.username }}
</a>
<div class="dropdown-menu dropdown-menu-right" aria-labelledby="us\
erMenu">
<a class="dropdown-item" href="{% url 'password_change' %}">Chan\
ge password</a>
Группа в ВК "Django_Python"
215
Chapter 10: Bootstrap
<div class="dropdown-divider"></div>
<a class="dropdown-item" href="{% url 'logout' %}">Log out</a>
</div>
</li>
</ul>
{% else %}
<form class="form-inline ml-auto">
<a href="{% url 'login' %}" class="btn btn-outline-secondary">Log in\
</a>
<a href="{% url 'signup' %}" class="btn btn-primary ml- ">Sign up</a>
</form>
{% endif %}
</div>
</nav>
<div class="container">
{% block content %}
{% endblock %}
</div>
<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery- . . .slim.min.js" integrity="sh\
a
-KJ o DKtIkvYIK UENzmM KCkRr/rE /Qpg aAZGJwFDMVNA/GpGFF
hXpG KkN" crossorig\
in="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/ .
per.min.js" integrity="sha
. /umd/pop\
-ApNbgh B+Y QKtv Rn W mgPxhU K/ScQsAP hUibX
j fakF\
PskvXusvfa b Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/ . . /js/bootstrap.mi\
Группа в ВК "Django_Python"
216
Chapter 10: Bootstrap
n.js" integrity="sha
-JZR Spejh U
d jOt vLEHfe/JQGiRRSQQxSfFWpi MquVdAyjUar +\
PVCmYl" crossorigin="anonymous"></script>
</body>
</html>
Если вы обновите домашнюю страницу на http://127.0.0.1:8000 наша новая навигационная
панель появится волшебным образом!
Homepage with Bootstrap nav logged in
Нажмите на имя пользователя в верхнем правом углу - wsv в моем случае - чтобы увидеть
хорошее выпадающее меню, которое предлагает Bootstrap.
Homepage with Bootstrap nav logged in and dropdown
Если вы нажмете на ссылку «logout», то наша навигационная панель изменится, предложив
ссылки либо «log in», либо «sign up».
Группа в ВК "Django_Python"
217
Chapter 10: Bootstrap
Homepage with Bootstrap nav logged out
Еще лучше, если вы уменьшите размер окна вашего браузера. Bootstrap автоматически
изменяет размеры и вносит изменения, чтобы он выглядел хорошо и на мобильном
устройстве.
Homepage mobile with hamburger icon
Обновите домашнюю страницу, и вы увидите ее в действии. Вы даже можете изменить
ширину веб-браузера, чтобы увидеть, как изменяются боковые поля при увеличении и
уменьшении размера экрана.
Если вы нажмете кнопку «logout», а затем «log in» в верхней панели навигации, вы также
увидите, что наша страница входа в систему http://127.0.0.1:8000/users/login также выглядит
лучше.
Группа в ВК "Django_Python"
218
Chapter 10: Bootstrap
Bootstrap login
Единственное, что отвлекает - это кнопка «Login». Мы можем использовать Bootstrap,
чтобы добавить приятный стиль, например сделать его зеленым и
привлекательным.Измените строку “button” в templates/registration/login.html следующим
образом.
Code
<!-- templates/registration/login.html -->
...
<button class="btn btn-success ml- " type="submit">Login</button>
...
Теперь обновите страницу, чтобы увидеть нашу новую кнопку.
Группа в ВК "Django_Python"
219
Chapter 10: Bootstrap
Bootstrap login with new button
Signup Form
Наша страница регистрации по адресу http://127.0.0.1:8000/users/signup/ есть стили
Bootstrap, а также отвлекающий вспомогательный текст. Например, после “Username”
написано “Required. 150 characters or fewer. Letters, digits and @/./+/-/_ only.”
Updated navbar logged out
Откуда взялся этот текст? Всякий раз, когда что-то кажется «волшебным» в Django, будьте
уверены, что это определенно не так. Вероятно, код пришел из внутреннего фрагмента
Django.
Самый быстрый метод, который я нашел, чтобы выяснить, что происходит в Django, просто перейти к исходному коду Django на Github, использовать панель поиска и
попытаться найти конкретный фрагмент текста.
Например, если вы выполните поиск «150 символов или меньше», вы окажетесь на
странице django / contrib / auth / models.py, расположенной, в строке 301.
Группа в ВК "Django_Python"
220
Chapter 10: Bootstrap
Текст поставляется как часть приложения auth, в поле имени пользователя для AbstractUser.
Сейчас у нас есть три варианта:
• переопределить существующий help_text
• скрыть help_text
• изменить стиль help_text
Мы выберем третий вариант, так как это хороший способ представить отличный
сторонний пакет django-crispy-forms. Работа с формами является сложной задачей, и
django-crispy-forms упрощает написание DRY кода.
Сначала остановите локальный сервер с Control+c. Затем используйте Pip env для
установки пакета в нашем проекте.
Command Line
(news) $ pipenv install django-crispy-forms
Добавьте новое приложение в список INSTALLED_APPS в settings.py файл. Поскольку
количество приложений начинает расти, я считаю полезным различать сторонние
приложения и локальные приложения, которые я добавил сам. Вот как сейчас выглядит
код.
Группа в ВК "Django_Python"
221
Chapter 10: Bootstrap
Code
# newspaper_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#
rd Party
'crispy_forms',
# Local
'users',
'pages',
]
Поскольку мы используем Bootstrap 4, мы также должны добавить эту конфигурацию в
settings.py файл. Это идет в нижней части файла.
Code
# newspaper_project/settings.py
CRISPY_TEMPLATE_PACK = 'bootstrap '
Теперь в нашем шаблоне signup.html мы можем быстро использовать crispy формы. Сначала мы
загружаем crispy_forms_tags сверху, а затем меняем {{ form.as_p }} на {{ form|crispy }}.
Группа в ВК "Django_Python"
222
Chapter 10: Bootstrap
Code
<!-- templates/signup.html -->
{% extends 'base.html' %}
{% load crispy_forms_tags %}
{% block title %}Sign Up{% endblock %}
{% block content %}
<h2>Sign up</h2>
<form method="post">
{% csrf_token %}
{{ form|crispy }}
<button type="submit">Sign up</button>
</form>
{% endblock %}
Если вы снова запустите сервер с помощью python manage.py runserver и обновите страницу
регистрации, мы увидим новые изменения.
Группа в ВК "Django_Python"
223
Chapter 10: Bootstrap
Crispy signup page
Намного лучше. Хотя, как насчет того, чтобы наша кнопка “Sign up” была немного более
привлекательной? В Bootstrap есть все виды стилей кнопок, которые мы можем выбрать.
Давайте использовать “success”, который имеет зеленый фон и белый текст.
Обновите файл signup.html в строке для кнопки регистрации.
Группа в ВК "Django_Python"
224
Chapter 10: Bootstrap
Code
<!-- templates/signup.html -->
...
<button class="btn btn-success" type="submit">Sign up</button>
...
Обновите страницу, и вы увидите нашу обновленную работу.
Crispy signup page green button
Следующий шаг
Наше приложение Newspaper начинает выглядеть довольно хорошо. Последний шаг это
настройка смены и сброса пароля.
Группа в ВК "Django_Python"
225
Chapter 10: Bootstrap
Здесь снова Django позаботился о тяжелой работе за нас, поэтому он требует минимального
количества кода с нашей стороны.
Группа в ВК "Django_Python"
Глава ��: Изменение и сброс пароля
В этой главе мы завершим поток авторизации нашего приложения Newspaper, добавив
функцию изменения и сброса пароля. Пользователи смогут изменить свой текущий пароль
или,
и
если
они
его
забыли
сбросить
его
по
электронной
почте.
Так же как в Django поставляется с встроенным представлением и URL для входа и выхода,
также поставляется и с views/URL смены и сброса пароля. Сначала мы рассмотрим версии
по умолчанию, а затем узнаем, как настроить их с помощью наших собственных шаблонов
Bootstrap и службы электронной почты.
Изменение пароля
Разрешение пользователям менять свои пароли является распространенной функцией на
многих веб-сайтах. Django предоставляет реализацию по умолчанию, которая уже работает
на этом этапе. Чтобы попробовать это, сначала нажмите кнопку “log in”, убедитесь, что вы
вошли в систему. Затем перейдите на страницу “Password change” по адресу
http://127.0.0.1:8000/users/password_change/.
Группа в ВК "Django_Python"
227
Chapter 11: Password Change and Reset
Password change
Введите старый пароль, а затем новый. Затем нажмите кнопку “Change My Password”.
Вы будете перенаправлены на страницу “Password change successful” (“пароль успешно изменен”),
расположенную по адресу:
http://127.0.0.1:8000/users/password_change/done/.
Password change done
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
228
Настройка изменения пароля
Давайте настроим эти две страницы смены пароля так, чтобы они соответствовали
внешнему виду нашего сайта газеты. Поскольку Django уже создал представления и URL
для нас, нам нужно только добавить новые шаблоны.
В командной строке создайте два новых файла шаблона в папке регистрации.
Command Line
(news) $ touch templates/registration/password_change_form.html
(news) $ touch templates/registration/password_change_done.html
Обновите password_change_form.html следующим кодом.
Code
<!-- templates/registration/password_change_form.html -->
{% extends 'base.html' %}
{% block title %}Password Change{% endblock %}
{% block content %}
<h1>Password change</h1>
<p>Please enter your old password, for security's sake, and then enter your ne\
w password twice so we can verify you typed it in correctly.</p>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-success" type="submit" value="Change my password">
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
229
</form>
{% endblock %}
В верхней части мы расширяем base.html и устанавливаем title нашей страницы. Поскольку
мы использовали title «block» в нашем файле base.html, мы можем переопределить их здесь.
Форма использует POST, так как мы отправляем данные и csrf_token по соображениям
безопасности. Используя form.as_p, мы просто отображаем в абзацах содержание формы
для сброса пароля по умолчанию. И, наконец, мы включаем кнопку отправки, которая
использует стиль Bootstrap btn btn-success, чтобы сделать его зеленым.Перейдите на
страницу http://127.0.0.1:8000/users/password_change/ и обновите страницу, чтобы увидеть
наши изменения.
New password change form
Следующий шаблон password_change_done.
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
230
Code
<!-- templates/registration/password_change_done.html -->
{% extends 'base.html' %}
{% block title %}Password Change Successful{% endblock %}
{% block content %}
<h1>Password change successful</h1>
<p>Your password was changed.</p>
{% endblock content %}
Он также расширяет base.html и включает новый title. Однако на странице нет формы,
только новый текст.Новая страница находится по адресу http://127.0.0.1:8000/users/
password_change/done/.
New password change done
Это было не так уж плохо, верно? Конечно, было гораздо меньше работы, чем создание
всего с нуля, особенно весь код вокруг безопасного обновления пароля пользователя. Далее
идет наша функция сброса пароля.
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
231
Сброс пароля
Сброс пароля обрабатывает частый случай, когда пользователи, забывают свои пароли.
Шаги очень похожи на настройку смены пароля, как мы только что делали. Django уже
предоставляет реализацию по умолчанию, которую мы будем использовать, а затем
настроим шаблоны, чтобы они соответствовали остальной части нашего сайта.
Единственная необходимая конфигурация указать Django, как отправлять электронные
письма. В конце концов, пользователь может сбросить пароль, только если у него есть
доступ к электронной почте, связанной с учетной записью. В производстве мы будем
использовать почтовый сервис SendGrid для фактической отправки электронных писем, но
в целях тестирования мы можем положиться на настройку бэкэнда консоли Django,
которая вместо этого выводит текст электронной почты в консоль командной строки.
Внизу файла settings.py сделайте следующее однострочное изменение.
Code
# newspaper_project/settings.py
EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
И у нас все готово! Джанго позаботится обо всем остальном за нас. Давайте
попробуем.Перейдите по адресу http://127.0.0.1:8000/users/password_reset/, чтобы
просмотреть страницу сброса пароля по умолчанию.
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
232
Default password reset page
Убедитесь, что введенный вами адрес электронной почты соответствует одной из ваших учетных
записей. После отправки вы будете перенаправлены на страницу сброса пароля по адресу:
http://127.0.0.1:8000/users/password_reset/done/.
Default password reset done page
Тут говорится , чтобы вы проверить вашу электронную почту. Так как мы указали Django
отправлять письма в консоль командной строки, текст письма теперь будет там. Это то, что
я вижу в своей консоли.
Группа в ВК "Django_Python"
233
Chapter 11: Password Change and Reset
Command Line
Content-Type: text/plain; charset="utf- "
MIME-Version:
.
Content-Transfer-Encoding:
bit
Subject: Password reset on
. . . :
From: webmaster@localhost
To: will@wsvincent.com
Date: Thu,
Mar
:
.
Message-ID: <
:
.
@ . . .
.in-addr.arpa>
You're receiving this email because you requested a password reset for your user\
account at
. . . :
.
Please go to the following page and choose a new password:
http://
. . . :
/users/reset/MQ/ up-
c
db ead
/
Your username, in case you've forgotten: wsv
Thanks for using our site!
The
. . . :
team
Текст письма должен быть одинаковым, за исключением трех строк:
• "кому” в шестой строке содержит адрес электронной почты пользователя
• ссылка URL содержит безопасный токен, который Django генерирует случайным
образом и может быть использован только один раз
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
234
• Django вежливо напоминает нам о вашем имени пользователя
В ближайшее время мы настроим весь текст электронного письма по умолчанию, но пока
сосредоточимся на поиске ссылки. В сообщении у меня:
http://127.0.0.1:8000/users/reset/MQ/4up-678712c114db2ead7780/
Введите эту ссылку в свой браузер и вы будете перенаправлены на страницу “смены
пароля”.
Default change password page
Теперь введите новый пароль и нажмите кнопку “Change my password”. Последним шагом
будет перенаправление вас на страницу “сброс пароля выполнен”.
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
Default password reset complete
Чтобы подтвердить, что все сработало, нажмите на ссылку “Log in” и используйте свой
новый пароль. Это должно сработать.
Собственные шаблоны
Как и в случае с “сменой пароля”, нам нужно только создать новые шаблоны, чтобы
настроить внешний вид сброса пароля.
Создайте четыре новых файла шаблонов.
Command Line
(news) $ touch templates/registration/password_reset_form.html
(news) $ touch templates/registration/password_reset_done.html
(news) $ touch templates/registration/password_reset_confirm.html
(news) $ touch templates/registration/password_reset_complete.html
Начните с формы сброса пароля, которым является password_reset_form.html.
Группа в ВК "Django_Python"
235
Chapter 11: Password Change and Reset
236
Code
<!-- templates/registration/password_reset_form.html -->
{% extends 'base.html' %}
{% block title %}Forgot Your Password?{% endblock %}
{% block content %}
<h1>Forgot your password?</h1>
<p>Enter your email address below, and we'll email instructions for setting a ne\
w one.</p>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-success" type="submit" value="Send me instructions!">
</form>
{% endblock %}
В верхней части мы расширяем base.html и устанавливаем titles нашей страницы.
Поскольку мы использовали titles «block» в нашем файле base.html, мы можем
переопределить их здесь. Форма использует POST, так как мы отправляем данные и
csrf_token по соображениям безопасности. Используя form.as_p, мы просто отображаем в
абзацах содержание формы для сброса пароля по умолчанию. Наконец, мы вставляем
кнопку отправки и используем стиль Bootstrap btn btn-success, чтобы сделать его зеленым.
Если вы перейдете по адресу http://127.0.0.1:8000/users/password_reset/ вы увидите нашу
новую страницу.
Группа в ВК "Django_Python"
237
Chapter 11: Password Change and Reset
New password reset
Теперь мы можем обновить остальные три страницы. Каждая из них имеет одинаковую
форму расширения base.html, нового заголовка, нового текста контента, а также для
«подтверждения сброса пароля» обновленную форму.
Code
<!-- templates/registration/password_reset_done.html -->
{% extends 'base.html' %}
{% block title %}Email Sent{% endblock %}
{% block content %}
<h1>Check your inbox.</h1>
<p>We've emailed you instructions for setting your password. You should receiv\
e the email shortly!</p>
{% endblock %}
Проверьте изменения, перейдя по ссылке http://127.0.0.1:8000/users/password_reset/done/.
Группа в ВК "Django_Python"
238
Chapter 11: Password Change and Reset
New reset done
Следующая страница подтверждения сброса пароля.
Code
<!-- templates/registration/password_reset_confirm.html -->
{% extends 'base.html' %}
{% block title %}Enter new password{% endblock %}
{% block content %}
<h1>Set a new password!</h1>
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
<input class="btn btn-success" type="submit" value="Change my password">
</form>
{% endblock %}
В командной строке выберите ссылку URL из электронного письма, выведенного на консоль - мое
было http://���.�.�.�:����/users/reset/MQ/�up-������c���db�ead����/ вы увидите
следующее.
Группа в ВК "Django_Python"
239
Chapter 11: Password Change and Reset
New set password
Наконец, вот полный код сброса пароля.
Code
<!-- templates/registration/password_reset_complete.html -->
{% extends 'base.html' %}
{% block title %}Password reset complete{% endblock %}
{% block content %}
<h1>Password reset complete</h1>
<p>Your new password has been set. You can log in now on the <a href="{% url 'lo\
gin' %}">log in page</a>.</p>
{% endblock %}
Вы можете просмотреть его по адресу http://127.0.0.1:8000/users/reset/done/.
Группа в ВК "Django_Python"
Chapter 11: Password Change and Reset
240
New password reset complete
Теперь пользователи могут сбросить свой пароль учетной записи!
Заключение
В следующей главе мы подключим наше приложение Newspaper
к почтовой службе
SendGrid, чтобы фактически отправлять наши автоматические электронные письма
пользователям, а не выводить их в нашей консоли командной строки.
Группа в ВК "Django_Python"
Глава ��: Email
На данный момент вы можете чувствовать себя немного перегруженным всей
информацией о конфигурации аутентификации пользователя, которую мы сделали до
этого момента. Это нормально. В конце концов, мы еще даже не создали каких либо
основных функций приложения Newspaper! Все было о настройке пользовательских
учетных записей пользователей и прочем.
Плюсом подхода Django является то, что в нем невероятно легко настроить любую часть нашего
сайта. Недостатком является то, что Django требует немного больше нестандартного кода, чем
некоторые конкурирующие веб-фреймворки. По мере того, как вы становитесь все более
опытным в веб-разработке, вы будете понимать мудрость подхода Django.
Теперь мы хотим, чтобы наши электронные письма отправлялись пользователям, а не
просто выводились в консоль командной строки. Нам нужно зарегистрироваться в
SendGrid и обновить ваш settings.py файл. Django позаботится об остальном. Готовы?
SendGrid
SendGrid это популярный сервис для отправки транзакционных писем, поэтому мы будем
использовать его. Django не заботится о том, какой сервис вы выбираете, хотя; вы можете
так же легко использовать MailGun или любой другой сервис по вашему выбору.
На главной странице SendGrid нажмите на большую синюю кнопку “See Plans and Pricing”.
Группа в ВК "Django_Python"
242
Chapter 12: Email
SendGrid homepage
На следующей странице немного прокрутите вниз и найдите в левой части кнопку “Try for Free”.
SendGrid предоставляет бесплатный уровень, который мы можем использовать, хотя они
несколько затрудняют его поиск.
Группа в ВК "Django_Python"
243
Chapter 12: Email
SendGrid pricing
Зарегистрируйте бесплатную учетную запись на следующей странице.
Группа в ВК "Django_Python"
244
Chapter 12: Email
SendGrid new account
Убедитесь, что учетная запись электронной почты, используемая для SendGrid, не
совпадает с учетной записью электронной почты суперпользователя в проекте Newspaper,
иначе могут быть странные ошибки.
После подтверждения вашей новой учетной записи по электронной почте вас попросят
войти в систему и перейти на страницу панели инструментов SendGrid.
Группа в ВК "Django_Python"
245
Chapter 12: Email
SendGrid loggedin
Теперь мы можем настроить наш код Django в файле settings.py. Сначала мы обновляем
почтовый сервер для использования SMTP.
Code
# newspaper_project/settings.py
EMAIL_BACKEND = 'django.core.mail.backends.smtp.EmailBackend'
Затем прямо под ним добавьте следующие пять строк конфигурации электронной почты.
Обратите внимание, что в идеале вы должны хранить защищенную информацию, такую
как ваш пароль, в переменной, но мы не будем этого делать здесь, что бы упростить
ситуацию.
Группа в ВК "Django_Python"
246
Chapter 12: Email
Code
# newspaper_project/settings.py
EMAIL_HOST = 'smtp.sendgrid.net'
EMAIL_HOST_USER = 'sendgrid_username'
EMAIL_HOST_PASSWORD = 'sendgrid_password'
EMAIL_PORT =
EMAIL_USE_TLS = True
Убедитесь, что вы используете свое собственное имя пользователя SendGrid для
EMAIL_HOST_USER и пароль для EMAIL_HOST_PASSWORD.
Вот и все. Мы закончили! Перейдите к форме сброса пароля снова на:
http://127.0.0.1:8000/users/password_reset/
Вы должны получить электронное письмо в свой почтовый ящик! Текст будет точно таким
же, как и в консоли командной строки ранее.
Пользовательские письма электронной почты
Текущий текст электронной почты не очень личный, не так ли? Давайте изменим. На этом
этапе я мог бы просто показать вам, какие шаги предпринять, но я думаю, что было бы
полезно, если бы я мог объяснить, как я понял, как это сделать. В конце концов, вы хотите
иметь возможность настраивать все части Django по мере необходимости.
В этом случае я знал, какой текст использовал Django по умолчанию, но не было ясно, где в
исходном коде Django он был написан. И поскольку весь исходный код Django доступен на
Github, мы можем просто найти его.
Группа в ВК "Django_Python"
247
Chapter 12: Email
Github Django
Используйте панель поиска Github и введите несколько слов из текста электронного
письма. Если вы введете “You’re receiving this email because”, вы попадете на страницу
поиска Github.
Github search
Первый результат - тот, который нам нужен. Он показывает, что код находится по адресу
django / contrib / ad-min / templates / registration / password_reset_email.html. Это означает,
что в приложении contrib файл который нам нужен, называется password_reset_email.html.
Группа в ВК "Django_Python"
248
Chapter 12: Email
Вот текст по умолчанию из исходного кода Django.
Code
{% load i
n %}{% autoescape off %}
{% blocktrans %}You're receiving this email because you requested a password res\
et for your user account at {{ site_name }}.{% endblocktrans %}
{% trans "Please go to the following page and choose a new password:" %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb
=uid token=to\
ken %}
{% endblock %}
{% trans "Your username, in case you've forgotten:" %} {{ user.get_username }}
{% trans "Thanks for using our site!" %}
{% blocktrans %}The {{ site_name }} team{% endblocktrans %}
{% endautoescape %}
Давайте изменим это. Нам нужно создать новый файл password_reset_email.html в нашей
папке registration .
Command Line
(news) $ touch templates/registration/password_reset_email.html
Затем используйте следующий код, который настраивает то, что Django предоставляет
по умолчанию.
Группа в ВК "Django_Python"
249
Chapter 12: Email
Code
<!-- templates/registration/password_reset_email.html -->
{% load i
n %}{% autoescape off %}
{% trans "Hi" %} {{ user.get_username }},
{% trans "We've received a request to reset your password. If you didn't make th\
is request, you can safely ignore this email. Otherwise, click the button below \
to reset your password." %}
{% block reset_link %}
{{ protocol }}://{{ domain }}{% url 'password_reset_confirm' uidb
=uid token=to\
ken %}
{% endblock %}
{% endautoescape %}
Этот код может выглядеть немного страшно, поэтому давайте разберем его построчно.
Вверху мы загружаем тег шаблона i18n, что означает, что этот текст может быть переведен
на несколько языков. Django имеет надежную поддержку интернационализации, хотя ее
охват выходит за рамки этой книги.
Мы приветствуем пользователя по имени благодаря user.get_username. Затем мы
используем встроенный блок reset_link для включения настраиваемой URL-ссылки. Вы
можете прочитать больше о подходе к управлению паролями Django в официальных
документах.
Давайте также обновим заголовок темы электронного письма. Для этого мы создадим
новый файл templates / registration / password_reset subject.txt.
Группа в ВК "Django_Python"
250
Chapter 12: Email
Command Line
(news) $ touch templates/registration/password_reset_subject.txt
Затем добавьте следующую строку кода в файл password_reset_subject.txt.
Please reset your password
И у нас все готово. Попробуйте снова наш новый поток, введя новый пароль по адресу
http://127.0.0.1:8000/users/password_reset/. Затем проверьте свою электронную почту, и она
будет иметь наш новый контент и тему.
Заключение
Теперь мы завершили реализацию полного процесса аутентификации пользователя.
Пользователи могут зарегистрировать новую учетную запись, войти в систему, выйти из
системы, изменить свой пароль и сбросить пароль. Пришло время создать наше
фактическое приложение Newspaper .
Группа в ВК "Django_Python"
Глава ��: приложение Newspaper
Пришло время создать наше приложение Newspaper. У нас будет страница статей, на
которой журналисты могут публиковать статьи, установим разрешения, чтобы только
автор статьи мог их редактировать или удалять, и, наконец, добавим возможность другим
пользователям писать комментарии к каждой статье, в которых будет введена концепция
внешних ключей.
Приложение Articles(статьи)
Для начала создайте приложение статей и определите модели нашей базы данных. Не
существует жестких и быстрых правил, касающихся имен ваших приложений, за
исключением того, что вы не можете использовать имя встроенного приложения. Если вы
посмотрите раздел INSTALLED_APPS файла settings.py, вы увидите, какие имена
приложений запрещены: admin, auth, contenttypes, sessions, messages, и staticfiles.. Общее
практическое правило заключается в использовании множественного числа имени
приложения - сообщений, платежей, пользователей и т. д. - если только это не является
явно неправильным, как в случае блога, где единственное число имеет больше смысла.
Start by creating our new articles app.
Command Line
(news) $ python manage.py startapp articles
Затем добавьте его в наш INSTALLED_APPS и обновите часовой пояс, так как мы будем
отмечать время в наших статьях. Вы можете найти свой часовой пояс в списке Википедии.
Например, я живу в Бостоне, штат Массачусетс, который находится в восточном часовом
поясе Соединенных Штатов. Поэтому моя запись - America/New_York.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
252
Code
# newspaper_project/settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
#
rd Party
'crispy_forms',
# Local
'users',
'pages',
'articles', # new
]
TIME_ZONE = 'America/New_York'
Далее мы определяем нашу модель базы данных, которая содержит четыре поля: заголовок,
тело, дата и автор. Обратите внимание, что мы позволяем Django автоматически
устанавливать время и дату в соответствии с нашей настройкой TIME_ZONE. В поле
автора мы хотим сослаться на нашу пользовательскую модель пользователя
users.CustomUser, которую мы установили в файле settings.py как AUTH_USER_MODEL.
Поэтому, если мы импортируем настройки, мы можем ссылаться на них как
settings.AUTH_USER_MODEL.
Мы также реализуем лучшие практики определения get_absolute_url с самого начала и
метод __str__ для просмотра модели в нашем интерфейсе администратора.
Группа в ВК "Django_Python"
253
Chapter 13: Newspaper app
Code
# articles/models.py
from django.conf import settings
from django.db import models
from django.urls import reverse
class Article(models.Model):
title = models.CharField(max_length=
)
body = models.TextField()
date = models.DateTimeField(auto_now_add=True)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', args=[str(self.id)])
Поскольку у нас есть совершенно новое приложение и модель, пришло время создать
новый файл миграции и затем применить его к базе данных.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
254
Command Line
(news) $ python manage.py makemigrations articles
(news) $ python manage.py migrate
На этом этапе мне нравится переходить в админку, чтобы поиграться с моделью, прежде
чем создавать urls/views/templates, необходимые для фактического отображения данных на
веб сайте. Но сначала нам нужно обновить admin.py, чтобы наше новое приложение
отобразилось.
Code
# articles/admin.py
from django.contrib import admin
from . import models
admin.site.register(models.Article)
Теперь мы запускаем сервер.
Command Line
(news) $ python manage.py runserver
Перейдите к http://127.0.0.1:8000/admin/ и войдите в систему.
Группа в ВК "Django_Python"
255
Chapter 13: Newspaper app
Admin page
Если вы нажмете “Articles” в верхней части страницы, мы сможем ввести некоторые
примеры данных. Скорее всего, на данный момент у вас будет три пользователя: ваши
учетные записи суперпользователя, testuser и testuser2. Используйте свой аккаунт
суперпользователя в качестве автора всех трех статей.
Группа в ВК "Django_Python"
256
Chapter 13: Newspaper app
Admin articles add page
Я добавил три новые статьи, как вы можете видеть на обновленной странице статей.
Группа в ВК "Django_Python"
257
Chapter 13: Newspaper app
Admin three articles
Если вы нажмете на отдельную статью, вы увидите, что отображаются title, body, и author, но не
дата. Это потому, что Django автоматически добавила нам дату и поэтому не может быть
изменена администратором. Мы могли бы сделать дату редактируемой - в более сложных
приложениях обычно есть поля create_at и updated_at - но для простоты мы просто покажем
дату создания. Даже если дата здесь не отображается, мы по-прежнему сможем получить к ней
доступ в наших шаблонах, чтобы ее можно было отображать на веб страницах.
URLs и Views
Следующий шаг - настройка URLs и представлений. Пусть наши статьи появятся в разделе
articles/. Импортируйте include во вторую строку и добавьте шаблон URL для статей на
уровне проекта файл urls.py.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
258
Code
# newspaper_project/urls.py
from django.contrib import admin
from django.urls import path, include # new
urlpatterns = [
path('', include('pages.urls')),
path('articles/', include('articles.urls')), # new
path('admin/', admin.site.urls),
path('users/', include('users.urls')),
path('users/', include('django.contrib.auth.urls')),
]
Далее мы создаем файл articles/urls.py.
Command Line
(news) $ touch articles/urls.py
Затем заполните его нашими маршрутами. Начнем со страницы со списком всех статей в
articles/ которая будет использовать представление ArticleListView.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
259
Code
# articles/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.ArticleListView.as_view(), name='article_list'),
]
Теперь создайте наше представление, используя встроенный универсальный ListView от Django
Code
# articles/views.py
from django.views.generic import ListView
from . import models
class ArticleListView(ListView):
model = models.Article
template_name = 'article_list.html'
Нам нужно указать только два поля: модель Article и имя нашего шаблона, который будет
article_list.html.
Последний шаг это создать наш шаблон. Мы можем сделать пустой файл из командной
строки.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
260
Command Line
(news) $ touch templates/article_list.html
Bootstrap имеет встроенный компонент под названием Cards , который мы можем
настроить для наших отдельных статей. Напомним, что ListView возвращает объект с
именем object_list, который мы можем перебрать с помощью цикла for.
В каждой статье мы показываем заголовок, текст, автора и дату. Мы даже можем
предоставить ссылки для «редактирования» и «удаления» функций, которые мы еще не
создали.
Code
<!-- templates/article_list.html -->
{% extends 'base.html' %}
{% block title %}Articles{% endblock %}
{% block content %}
{% for article in object_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ article.title }}</span> ·
<span class="text-muted">by {{ article.author }} | {{ article.date }}</s\
pan>
</div>
<div class="card-body">
{{ article.body }}
</div>
<div class="card-footer text-center text-muted">
<a href="#">Edit</a> | <a href="#">Delete</a>
Группа в ВК "Django_Python"
261
Chapter 13: Newspaper app
</div>
</div>
<br />
{% endfor %}
{% endblock content %}
Снова запустите сервер с помощью python manage.py runserver и посетите нашу страницу
по адресу http://127.0.0.1:8000/articles/.
Articles page
Не плохо а? Если бы мы захотели проявить фантазию, мы могли бы создать собственный
шаблонный фильтр, чтобы выводимая дата отображалась в секундах, минутах или днях.
Это можно сделать с помощью некоторой логики if / else и опций даты в Django, но мы не
будем реализовывать это здесь.
Группа в ВК "Django_Python"
262
Chapter 13: Newspaper app
Редактирование/Удаление
Как мы можем добавить параметры редактирования и удаления? Нам нужны новые urls,
представления и шаблоны. Давайте начнем с urls. Мы можем воспользоваться тем, что
Django автоматически добавляет первичный ключ в каждую базу данных. Поэтому наша
первая статья с первичным ключом 1 будет находиться в article / 1 / edit /, а маршрут удаления
будет находиться в article / 1 / delete /.
Code
# articles/urls.py
from django.urls import path
from . import views
urlpatterns = [
path('', views.ArticleListView.as_view(), name='article_list'),
path('<int:pk>/edit/',
views.ArticleUpdateView.as_view(), name='article_edit'),
# new
path('<int:pk>/',
views.ArticleDetailView.as_view(), name='article_detail'),
# new
path('<int:pk>/delete/',
views.ArticleDeleteView.as_view(), name='article_delete'),
# new
]
Теперь запишите наши представления, которые будут использовать представления на
основе классов Django для DetailView, UpdateView и DeleteView. Мы указываем, какие поля могут
быть обновлены - заголовок и тело - и куда перенаправлять пользователя после удаления
статьи: article_list.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
Code
# articles/views.py
from django.views.generic import ListView, DetailView
from django.views.generic.edit import UpdateView, DeleteView
from django.urls import reverse_lazy
from . import models
class ArticleListView(ListView):
model = models.Article
template_name = 'article_list.html'
class ArticleDetailView(DetailView):
model = models.Article
template_name = 'article_detail.html'
class ArticleUpdateView(UpdateView):
model = models.Article
fields = ['title', 'body', ]
template_name = 'article_edit.html'
class ArticleDeleteView(DeleteView):
model = models.Article
template_name = 'article_delete.html'
Группа в ВК "Django_Python"
263
Chapter 13: Newspaper app
264
success_url = reverse_lazy('article_list')
Наконец нам нужно добавить наши новые шаблоны. Остановите сервер с помощью Control
+ c и введите следующее.
Command Line
(news) $ touch templates/article_detail.html
(news) $ touch templates/article_edit.html
(news) $ touch templates/article_delete.html
Мы начнем со страницы details , где будут отображаться заголовок, дата, тело и автор со
ссылками для редактирования и удаления. Она также будет ссылаться на все статьи.
Напомним, что тегу url языка шаблонов Django требуется имя URL, а затем передаются все
аргументы. Имя нашего маршрута редактирования - article_edit, и нам нужно передать его
первичный ключ article.pk. Имя маршрута для удаления - article_delete, для него также
требуется первичный ключ article.pk. Наша страница статей представляет собой ListView,
поэтому ей не нужно передавать никаких дополнительных аргументов.
Code
<!-- templates/article_detail.html -->
{% extends 'base.html' %}
{% block content %}
<div class="article-entry">
<h2>{{ object.title }}</h2>
<p>by {{ object.author }} | {{ object.date }}</p>
<p>{{ object.body }}</p>
</div>
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
265
<p><a href="{% url 'article_edit' article.pk %}">Edit</a> | <a href="{% url 'a\
rticle_delete' article.pk %}">Delete</a></p>
<p>Back to <a href="{% url 'article_list' %}">All Articles</a>.</p>
{% endblock content %}
Для редактирования и удаления страниц мы можем использовать стиль кнопок Bootstrap,
чтобы кнопка редактирования была светло-голубой, а кнопка удаления - красной.
Code
<!-- templates/article_edit.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Edit</h1>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-info ml- " type="submit">Update</button>
</form>
{% endblock %}
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
266
Code
<!-- templates/article_delete.html -->
{% extends 'base.html' %}
{% block content %}
<h1>Delete</h1>
<form action="" method="post">{% csrf_token %}
<p>Are you sure you want to delete "{{ article.title }}"?</p>
<button class="btn btn-danger ml- " type="submit">Confirm</button>
</form>
{% endblock %}
В качестве заключительного шага мы можем добавить ссылки редактировать и удалять на нашу страницу list в классе div для
card-footer.... Они будут такими же, как те, которые добавлены на страницу detail.
Code
<!-- templates/article_list.html -->
...
<div class="card-footer text-center text-muted">
<a href="{% url 'article_edit' article.pk %}">Edit</a> |
<a href="{% url 'article_delete' article.pk %}">Delete</a>
</div>
...
Хорошо, мы готовы посмотреть нашу работу. Запустите сервер с помощью python
manage.py runserver и перейдите на страницу статей http://127.0.0.1:8000/articles/. Нажмите
на ссылку "edit” в первой статье, и вы будете перенаправлены на:
http://127.0.0.1:8000/articles/1/edit/
Группа в ВК "Django_Python"
267
Chapter 13: Newspaper app
Edit page
Если вы обновите поле “title” и нажмете кнопку update , вы будете перенаправлены на
страницу detail, которая показывает изменение.
Detail page
Если вы нажмете на ссылку “Delete” вы будете перенаправлены на страницу delete.
Группа в ВК "Django_Python"
268
Chapter 13: Newspaper app
Delete page
Нажмите страшную красную кнопку для “Delete”, и вы будете перенаправлены на страницу
статей, которая теперь имеет только две записи.
Articles page two entries
Создание страницы
Последним шагом является создание страницы для новых статей, которые мы можем
сделать с Django CreateView. Наши три шага - это создание представления, url-адреса и
шаблона. Этот процесс должен быть уже довольно знакомым.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
269
В нашем файле представлений добавьте Create View к импорту вверху и создайте новый
класс ArticleCreateView Create View, который указывает вашу модель, шаблон и доступные
поля.
Code
# articles/views.py
...
from django.views.generic.edit import CreateView, UpdateView, DeleteView
class ArticleCreateView(CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title', 'body', 'author',]
...
Обратите внимание, что у наших полей есть автор, так как мы хотим связать новую статью
с автором, однако после создания статьи мы не хотим, чтобы пользователь мог изменить
автора, поэтому ArticleUpdateView имеет только поля ['title', 'body',].
Обновите файл url новым маршрутом для представления.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
270
Code
# articles/urls.py
...
urlpatterns = [
...
path('new/', views.ArticleCreateView.as_view(), name='article_new'),
...
]
Затем остановите сервер с Control+c, чтобы создать новый шаблон с именем article_new.html.
Command Line
(news) $ touch templates/article_new.html
И обновите его следующим HTML кодом.
Code
<!-- templates/article_new.html -->
{% extends 'base.html' %}
{% block content %}
<h1>New article</h1>
<form action="" method="post">{% csrf_token %}
{{ form.as_p }}
<button class="btn btn-success ml- " type="submit">Save</button>
</form>
{% endblock %}
В качестве заключительного шага мы должны добавить ссылку на создание новых статей в
нашей панели навигации, чтобы она была доступна везде на сайте для зарегистрированных
пользователей.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
271
Code
<!-- templates/base.html -->
...
<body>
<nav class="navbar navbar-expand-md navbar-dark bg-dark mb- ">
<a class="navbar-brand" href="{% url 'home' %}">Newspaper</a>
{% if user.is_authenticated %}
<ul class="navbar-nav mr-auto">
<li class="nav-item"><a href="{% url 'article_new' %}">+ New</a></li>
</ul>
{% endif %}
<button class="navbar-toggler" type="button" data-toggle="collapse" data-tar\
get="#navbarCollapse" aria-controls="navbarCollapse" aria-expanded="false" aria-\
label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
...
И почему бы не использовать Bootstrap, чтобы улучшить нашу оригинальную домашнюю
страницу? Мы можем обновить templates/home.html следующим образом.
Группа в ВК "Django_Python"
Chapter 13: Newspaper app
272
Code
<!-- templates/home.html -->
{% extends 'base.html' %}
{% block title %}Home{% endblock %}
{% block content %}
<div class="jumbotron">
<h1 class="display- ">Newspaper app</h1>
<p class="lead">A Newspaper website built with Django.</p>
<p class="lead">
<a class="btn btn-primary btn-lg" href="{% url 'article_list' %}" role="butt\
on">View All Articles</a>
</p>
</div>
{% endblock %}
Мы все закончили. Давайте просто подтвердим, что все работает, как ожидалось. Запустите
сервер снова python manage.py runserver и перейдите на нашу домашнюю страницу по адресу:
http://127.0.0.1:8000/.
Группа в ВК "Django_Python"
273
Chapter 13: Newspaper app
Homepage with new link in nav
Нажмите на ссылку " + New” в верхней панели навигации, и вы будете перенаправлены на
нашу страницу создания.
Группа в ВК "Django_Python"
274
Chapter 13: Newspaper app
Create page
Продолжайте и создайте новую статью. Затем нажмите на кнопку “Save”. Вы будете
перенаправлены на страницу detail . Почему? Потому что в нашем models.py файл мы
устанавливаем метод get_-absolute_url в article_detail. Это хороший подход, потому что если
мы позже изменим шаблон url для страницы detail, скажем, на articles/details/4/,
перенаправление все равно будет работать.
Какой бы маршрут не был связан с
article_detail, будет применятся; нет жесткого кодирования самого маршрута.
Группа в ВК "Django_Python"
275
Chapter 13: Newspaper app
Detail page
Также обратите внимание, что первичный ключ здесь 4 в URL. Хотя сейчас мы показываем
только три статьи, Django не переупорядочивает первичные ключи только потому, что мы
удалили один. На практике большинство реальных сайтов ничего не удаляют; вместо этого
они «скрывают» удаленные поля, поскольку это облегчает поддержание целостности базы
данных и дает возможность «восстановить» позже, если это необходимо. С нашим текущим
подходом, как только что-то удалено, оно ушло навсегда!
Нажмите на ссылку “All Articles”, чтобы увидеть нашу новую страницу /articles page.
Группа в ВК "Django_Python"
276
Chapter 13: Newspaper app
Updated articles page
Как и ожидалось, внизу есть наша новая статья.
Заключение
Мы создали специальное приложение article с функцией CRUD. Но пока нет никаких
разрешений или авторизаций, что означает, что каждый может сделать что угодно!
Пользователь, вышедший из системы, может просматривать все url, а любой пользователь,
вошедший в систему, может вносить изменения или удалять в существующую статью, даже
если она не принадлежит им! В следующей главе мы добавим разрешения и авторизации в
наш проект, чтобы это исправить.
Группа в ВК "Django_Python"
Глава ��:Разрешения и авторизация
Есть несколько проблем с нашим текущим сайтом газеты. Во первых, мы хотим, чтобы
наша газета была финансово устойчивой. В будущем мы могли бы добавить платежное
приложение, чтобы взимать плату за доступ, но сейчас нам потребуется, чтобы
пользователь вошел в систему для просмотра любых статей. Это известно как авторизация.
Распространено устанавливать разные правила относительно того, кто имеет право
просматривать области вашего сайта. Обратите внимание, что это отличается от
аутентификации, которая представляет собой процесс регистрации и входа в систему
пользователей.
Авторизация
ограничивает
доступ;
Аутентификация
позволяет
пользователю зарегистрироваться и войти в систему.
Как развитый веб фреймворк, Django имеет встроенную функциональность для
авторизации, которую мы можем быстро использовать. В этой главе мы ограничим доступ
к различным страницам открыв его только зарегистрированным пользователям. Мы также
добавим разрешения, чтобы только автор статьи мог ее обновить или удалить; На данный
момент это может сделать любой пользователь!
Улучшение CreateView
В настоящее время автором новой статьи может быть задан любой пользователь. Вместо
этого он должен быть автоматически установлен как текущий пользователь. Затем мы
установим права на редактирование / удаление, чтобы такие изменения мог вносить только
автор статьи. Созданный по умолчанию CreateView предоставляет нам множество
функциональных возможностей, но для того, чтобы назначить текущего пользователя
автором, нам нужно его настроить. Мы удалим автора из полей и вместо этого установим
его автоматически с помощью метода form_valid.
Группа в ВК "Django_Python"
Chapter 14: Permissions and Authorization
278
Code
# articles/views.py
...
class ArticleCreateView(CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title', 'body']
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
...
Как я узнал, что могу обновить CreateView следующим образом? Ответ я посмотрел на
исходный код и использовал Google. Представления на основе классов отлично подходят
для запуска новых проектов, но когда вы хотите настроить их, необходимо засучить рукава
и начать понимать, что происходит под капотом. Чем больше вы используете и
настраиваете встроенные представления, тем удобнее вам будет выполнять такие
настройки. Скорее всего, то, что вы пытаетесь сделать, уже где-то решено, либо в самом
Django, либо на форуме, подобно Stack Overflow. Не бойтесь просить о помощи!
Теперь перезагрузите браузер и попробуйте нажать на ссылку “+ New” в верхней части
окна. Это перенаправит на обновленную страницу создания, где больше нет поля автор.
Если вы создадите новую статью, а затем зайдете в админку, вы увидите, что она
автоматически настроена для текущего вошедшего в систему пользователя.
Группа в ВК "Django_Python"
279
Chapter 14: Permissions and Authorization
New article link
Авторизация
Существует множество проблем, связанных с отсутствием разрешений в нашем текущем
проекте. Очевидно, что мы хотели бы ограничить доступ оставив его только для
пользователей, поэтому у нас есть возможность в один прекрасный день наполнить
читателями нашу газету . Но помимо этого, любой случайный пользователь, вышедший из
системы, который знает правильный URL, может получить доступ к любой части сайта.
Подумайте, что произойдет, если вышедший из системы пользователь попытается создать
новую статью? Чтобы попробовать, нажмите на свое имя пользователя в правом верхнем
углу навигационной панели, затем выберите “Log out” из выпадающих меню. Ссылка“+
New” исчезает из навигационной панели, но что произойдет, если вы перейдете к ней
напрямую: http://127.0.0.1:8000/articles/new/?
Страница все еще здесь.
Группа в ВК "Django_Python"
Chapter 14: Permissions and Authorization
280
Logged out new
Теперь попробуйте создать новую статью с заголовком и телом. Нажмите на кнопку “Save”.
Create page error
Группа в ВК "Django_Python"
Chapter 14: Permissions and Authorization
281
Ошибка. Это связано с тем, что в нашей модели ожидается поле автора, которое связано с
текущим вошедшим пользователем. Но поскольку мы не вошли в систему, автора нет, и
поэтому отправка не удалась.
Mixins(Миксины)
Мы явно хотим установить некоторые полномочия, чтобы только зарегистрированные
пользователи могли получить доступ к сайту. Для этого мы можем использовать миксин,
который представляет собой особый вид множественного наследования, который
использует Django, чтобы избежать дублирования кода и сделать возможной настройку.
Например, встроенному универсальному ListView необходим способ возврата шаблона, так
же, как и DetailView, и практически любой другое представление. Вместо того, чтобы
повторять один и тот же код в каждом большом общем представлении, Django разбивает
эту функциональность на «миксин», известный как TemplateRespon-seMixin. И ListView, и
DetailView используют этот миксин для визуализации правильного шаблона.
IЕсли вы прочитаете исходный код Django, который свободно доступен на Github, вы
увидите, что миксины используются повсеместно.
Чтобы ограничить доступ к просмотру оставив его только зарегистрированным
пользователям, Django имеет миксин LoginRequired, который мы можем использовать. Он
мощный и очень краткий.
В существующем файле article / views.py импортируйте его вверху, а затем добавьте
LoginRequiredMixin в наш ArticleCreateView. Убедитесь, что миксин находится слева от
ListView, чтобы он читался первым. Мы хотим, чтобы ListView уже знал, что мы намерены
ограничить доступ.
И это все! Мы закончили.
Группа в ВК "Django_Python"
282
Chapter 14: Permissions and Authorization
Code
# articles/views.py
from django.contrib.auth.mixins import LoginRequiredMixin # new
...
class ArticleCreateView(LoginRequiredMixin, CreateView): # new
...
Вернитесь к URL создания новых сообщений по адресу http://127.0.0.1:8000/articles/new/, и вы
увидите следующую ошибку:
Error page
Что происходит? Django автоматически перенаправил нас в местоположение по умолчанию
для страницы входа в систему, которое находится по адресу / account / login, однако, если
вы помните, в наших URL уровня проекта мы используем users/ в качестве маршрута. Вот
почему наша страница авторизации находится на сайте users / login. Так как же нам
рассказать об этом в ArticleCreateView?
Если вы посмотрите на документацию для LoginRequired mixin, она скажет нам ответ. Мы
можем добавить login_url для переопределения параметра по умолчанию. Мы используем
именованный URL маршрут входа в систему.
Группа в ВК "Django_Python"
Chapter 14: Permissions and Authorization
283
Code
# articles/views.py
...
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title', 'body',]
login_url = 'login' # new
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Попробуйте ссылку для создания новых сообщений еще раз: http://127.0.0.1:8000/articles/new/.
Теперь она перенаправляет пользователей на страницу входа. Как мы и хотели!
Updating views
Теперь мы видим, что ограничение доступа к представлению - это просто добавление
LoginRequiredMixin в начале всех существующих представлений и указание правильного
login_url. Давайте обновим остальные представления наших статей, поскольку мы не
хотим, чтобы пользователь мог создавать, читать, обновлять или удалять сообщения, если
они не вошли в систему.
Полностью файл views.py теперь должен выглядеть следующим образом:
Группа в ВК "Django_Python"
Chapter 14: Permissions and Authorization
Code
# articles/views.py
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import ListView, DetailView
from django.views.generic.edit import CreateView, UpdateView, DeleteView
from django.urls import reverse_lazy
from . import models
class ArticleListView(LoginRequiredMixin, ListView):
model = models.Article
template_name = 'article_list.html'
login_url = 'login'
class ArticleDetailView(LoginRequiredMixin, DetailView):
model = models.Article
template_name = 'article_detail.html'
login_url = 'login'
class ArticleUpdateView(LoginRequiredMixin, UpdateView):
model = models.Article
fields = ['title', 'body', ]
template_name = 'article_edit.html'
login_url = 'login'
Группа в ВК "Django_Python"
284
Chapter 14: Permissions and Authorization
285
class ArticleDeleteView(LoginRequiredMixin, DeleteView):
model = models.Article
template_name = 'article_delete.html'
success_url = reverse_lazy('article_list')
login_url = 'login'
class ArticleCreateView(LoginRequiredMixin, CreateView):
model = models.Article
template_name = 'article_new.html'
fields = ['title', 'body', ]
login_url = 'login'
def form_valid(self, form):
form.instance.author = self.request.user
return super().form_valid(form)
Далее поиграйте с сайтом, чтобы убедиться, что перенаправления входа в систему теперь
работают как положено. Если вам нужна помощь, чтобы вспомнить, какие правильные
URLs, сначала войдите в систему и запишите URLs для каждого из маршрутов создания,
редактирования, удаления и страницы всех статей.
Заключение
Наше приложение Newspaper почти готово. Наши статьи правильно настроены, настроены
разрешения и авторизация, аутентификация пользователя в хорошем состоянии.
Последний пункт это добавить возможность другим зарегистрированным пользователям
оставлять комментарии, о которых мы расскажем в следующей главе.
Группа в ВК "Django_Python"
Глава ��: Комментарии
Есть два способа добавить комментарии на сайт нашей газеты. Первый - создать
специальное приложение comments и связать его с articles, однако на данный момент это
похоже на чрезмерное проектирование. Вместо этого мы можем просто добавить
дополнительную модель comment в наше приложение articles и связать ее с моделью Article
с помощью внешнего ключа. К концу этой главы пользователи смогут оставлять
комментарии к статьям других пользователей.
Модель
Для начала мы можем добавить еще одну таблицу в нашу существующую базу данных под
названием Comment. Эта модель будет иметь связь внешнего ключа многие-к-одному к Article:
одна статья может иметь много комментариев, но не наоборот. Традиционно поле
внешнего ключа называется просто моделью, на которую оно ссылается, поэтому это поле
будет называться article. Остальные два поля будут comment и author.
Откройте файл articles/models.py и под существующим кодом добавьте следующее.
Группа в ВК "Django_Python"
287
Chapter 15: Comments
Code
# articles/models.py
...
class Comment(models.Model):
article = models.ForeignKey(Article, on_delete=models.CASCADE)
comment = models.CharField(max_length=
)
author = models.ForeignKey(
settings.AUTH_USER_MODEL,
on_delete=models.CASCADE,
)
def __str__(self):
return self.comment
def get_absolute_url(self):
return reverse('article_list')
Наша модель Comment также имеет метод __str__ и метод get_absolute_url, который
возвращает на страницу статьи.
Поскольку мы обновили наши модели, пришло время создать новый файл миграции и
применить его. Обратите внимание, что мы добавляем articles в конец команды, что
является необязательным, мы указываем, что хотим использовать в миграции только
приложение articles. Это хорошая привычка. Например, что делать, если мы внесли
изменения в модели в двух разных приложениях? Если бы мы не указали приложение, то
изменения обоих приложений были бы включены в один и тот же файл миграции, что
затруднит в будущем отладку ошибок. Держите каждую миграцию как можно компактнее и
сдержаннее.
Группа в ВК "Django_Python"
288
Chapter 15: Comments
Command Line
(news) $ python manage.py makemigrations articles
(news) $ python manage.py migrate
Admin
После создания новой модели хорошо поиграть с ней в приложении администратора,
прежде чем отображать ее на нашем фактическом веб сайте. Добавьте Comment к вашему
файлу admin.py что бы он был виден.
Code
# articles/admin.py
from django.contrib import admin
from . import models
admin.site.register(models.Article)
admin.site.register(models.Comment)
Запустите сервер с помощью python manage.py runserver и перейдите на нашу главную страницу
админки http://127.0.0.1:8000/admin/
Группа в ВК "Django_Python"
289
Chapter 15: Comments
Admin page with Comments
Под нашим приложением “Articles” вы увидите две таблицы: Comments и Articles. Нажмите
на кнопку “+ Add” рядом с Comments. Вы увидите, что под статьей находится выпадающий
список существующих статей, то же самое для автора, и есть текстовое поле рядом с
Comment.
Группа в ВК "Django_Python"
290
Chapter 15: Comments
Admin Comments
Выберите статью, напишите комментарий, а затем выберите автора, который не является
вашим суперпользователем, возможно, testuser, как я сделал на картинке. Затем нажмите на
кнопку “Save”.
Вы должны увидеть свой комментарий на странице “Comments”.
Группа в ВК "Django_Python"
291
Chapter 15: Comments
Admin Comment One
На этом этапе мы можем добавить дополнительное поле администратора, чтобы увидеть комментарий и
статью на этой странице. Но не лучше ли просто просмотреть все модели комментариев, связанные с одной
моделью публикации? Оказывается, мы это можем ,с помощью функции Django admin называемой inlines,
которая отображает внешние ключевые связи приятным визуальным способом.
Используются два основных встроенных представления: TabularInline и StackedInline.
Единственное различие между ними - это шаблон для отображения информации. В
TabularInline все поля модели отображаются в одной строке, в то время как в StackedInline
каждое поле имеет свою собственную строку. Мы реализуем оба, так что вы сами можете
решить, какой из них вам выбрать.
Обновите articles/admin.py следующим образом в текстовом редакторе.
Группа в ВК "Django_Python"
292
Chapter 15: Comments
Code
# articles/admin.py
from django.contrib import admin
from . import models
class CommentInline(admin.StackedInline):
model = models.Comment
class ArticleAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
admin.site.register(models.Article, ArticleAdmin)
admin.site.register(models.Comment)
Теперь вернитесь на главную страницу администратора по адресу http://127.0.0.1:8000/admin/ и
нажмите “Articles”. Выберите статью, для которой вы только что добавили комментарий, в
моем случае была “Local news”.
Группа в ВК "Django_Python"
293
Chapter 15: Comments
Admin change page
Лучше, не правда ли? Мы можем просматривать и изменять все связанные статьи и
комментарии в одном месте.
Хотя лично я предпочитаю использовать TabularInline, поскольку он показывает больше
информации в меньшем пространстве. Чтобы переключиться на него, нам нужно только
изменить ваш CommentInline от admin.StackedInline к admin.TabularInline.
Группа в ВК "Django_Python"
294
Chapter 15: Comments
Code
# articles/admin.py
from django.contrib import admin
from . import models
class CommentInline(admin.TabularInline):
model = models.Comment
class ArticleAdmin(admin.ModelAdmin):
inlines = [
CommentInline,
]
admin.site.register(models.Article, ArticleAdmin)
admin.site.register(models.Comment)
Обновите страницу администратора и вы увидите новое изменение: все поля для каждой
модели отображаются в одной строке.
Группа в ВК "Django_Python"
295
Chapter 15: Comments
TabularInline page
Намного лучше. Теперь нам нужно обновить шаблон для отображения комментариев.
Template(шаблон)
Поскольку Comment находится в нашем существующем приложении articles , нам нужно
только обновить существующие шаблоны для article_list.html и article_detail.html для
отображения нашего нового контента. Нам не нужно создавать новые шаблоны и возиться
с urls и представлениями.
То, что мы хотим сделать, это отобразить все комментарии, связанные с конкретной
статьей. Это называется “query”, поскольку мы запрашиваем у базы данных определенный
бит информации. В нашем случае, работая с внешним ключом, мы хотим проследить
обратную связь: в каждой статье ищем связанные модели Comment.
Группа в ВК "Django_Python"
296
Chapter 15: Comments
Django имеет встроенный синтаксис, который мы можем использовать известный как
FOO_set, где FOO - это имя исходной модели в нижнем регистре. Таким образом, для нашей
модели Article мы можем использовать article_set для доступа ко всем экземплярам модели.
Но лично мне сильно не нравится этот синтаксис, поскольку я нахожу его запутанным и
неинтуитивным. Лучший подход это добавить атрибут related_name в нашу модель, который
позволяет явно задать имя этой обратной связи. Давайте сделаем это.
Для начала добавьте атрибут related_name в нашу модель Comment. Хорошим значением
по умолчанию является множественное число модели с ForeignKey.
Code
# articles/models.py
...
class Comment(models.Model):
article = models.ForeignKey(
Article,
on_delete=models.CASCADE,
related_name='comments' # new
)
Поскольку мы только что внесли изменения в нашу модель базы данных, нам нужно
создать файл миграции и обновить базу данных. Остановите локальный сервер с помощью
Control+c и выполните следующие две команды. Затем снова запустите сервер, мы будем
использовать его в ближайшее время.
Группа в ВК "Django_Python"
297
Chapter 15: Comments
Command Line
(news) $ python manage.py makemigrations articles
(news) $ python manage.py migrate
(news) $ python manage.py runserver
Понимание запросов занимает некоторое время, поэтому не беспокойтесь, если идея
обратных связей запутана. Я покажу вам, как реализовать код по желанию. И как только вы
освоите эти основные примеры, вы сможете изучить, как фильтровать свои наборы
запросов очень подробно, чтобы они возвращали именно ту информацию, которую вы
хотите.
В нашем файле article_list.html мы можем добавить наши комментарии в card-footer. Обратите
внимание, что я перенес наши изменения и удалил ссылки в card-body. Чтобы получить
доступ к каждому комментарию, мы вызываем article.comments.all, что означает сначала
посмотреть на модель article , а затем comments, которые являются связанным именем всей
модели Comment, и выбрать все включенные. Может потребоваться некоторое время,
чтобы привыкнуть к этому синтаксису для ссылки на данные внешнего ключа в шаблоне!
Code
<!-- template/article_list.html -->
{% extends 'base.html' %}
{% block title %}Articles{% endblock %}
{% block content %}
{% for article in object_list %}
<div class="card">
<div class="card-header">
<span class="font-weight-bold">{{ article.title }}</span> ·
<span class="text-muted">by {{ article.author }} | {{ article.date }}</s\
Группа в ВК "Django_Python"
298
Chapter 15: Comments
pan>
</div>
<div class="card-body">
<p>{{ article.body }}</p>
<a href="{% url 'article_edit' article.pk %}">Edit</a> |
<a href="{% url 'article_delete' article.pk %}">Delete</a>
</div>
<div class="card-footer">
{% for comment in article.comments.all %}
<p>
<span class="font-weight-bold">{{ comment.author }} ·</span>
{{ comment }}
</p>
{% endfor %}
</div>
</div>
<br />
{% endfor %}
{% endblock content %}
Если мы обновим страницу articles по адресу http://127.0.0.1:8000/articles/, мы увидим наш
новый комментарий, отображаемый на странице.
Группа в ВК "Django_Python"
299
Chapter 15: Comments
Articles page with comments
Эй! Это работает. Мы можем видеть оба комментария, перечисленные под сообщением.
Заключение
С большим количеством времени мы бы сосредоточились на формах, чтобы пользователь
мог написать новую статью прямо на странице articles , а также добавить комментарии. Но
главная цель этой главы - показать, как работают связи с внешними ключями в Django.
Наше
приложение
Newspaper
теперь
завершено.
Оно
имеет
надежный
поток
аутентификации пользователя, включая использование электронной почты для сброса
паролей. Мы также используем CustomUser, поэтому, если мы хотим добавить
дополнительные поля в нашу пользовательскую модель, это так же просто, как добавить
дополнительное поле.
Группа в ВК "Django_Python"
300
Chapter 15: Comments
У нас уже есть поле возраста для всех пользователей, которое в настоящее время
устанавливается в 0 по умолчанию. Если бы мы хотели, мы могли бы добавить возрастное
раскрывающееся меню в форму регистрации и ограничить доступ пользователей только
для пользователей старше 13 лет. Или мы можем предложить скидки пользователям
старше 65 лет. Все, что мы захотим сделать с нашей CustomUser моделью, является опцией.
Большинство веб-разработок следуют тем же шаблонам и с помощью веб фреймворка,
такого как Django 99% того, что мы хотим сделать, с точки зрения функциональности либо
уже включено либо требуется небольшая настройка существующей функции.
Группа в ВК "Django_Python"
Заключение
Поздравляем с окончанием Django для начинающих! Начав с абсолютного нуля, мы
создали пять различных веб приложений с нуля. Мы рассмотрели все основные функции
Django: шаблоны, представления, urls, пользователей, модели, безопасность, тестирование
и развертывание. Теперь у вас есть знания, чтобы идти дальше и создавать свои
собственные современные веб сайты с Django.
Как и в случае с любым новым навыком, важно практиковать и применять то, что вы
только что узнали. Функциональность CRUD в нашем блоге и газете распространена во
многих, многих других веб приложениях. Например, можно ли создать веб приложение
списка задач? У вас уже есть все необходимые инструменты.
Веб разработка это очень глубокая область, и есть еще многое, что узнать о том, что Django
может предложить. Например, более продвинутый проект Django, скорее всего, будет
использовать несколько файлов настроек, переменных и PostgreSQL локально вместо
SQLite. Он может даже использовать сторонние пакеты, такие как django-allauth для
социальной аутентификации, django-debug-toolbar для отладки и django-extensions для
дополнительных вкусностей.
Лучший способ узнать больше о Django и веб разработке в целом это подумать о проекте,
который вы хотите построить, а затем шаг за шагом узнать, что вам нужно для его
завершения. Дополнительным ресурсом, который может помочь, является DjangoX,
который
является
реальным
стартовым
проектом,
который
имеет
социальную
аутентификацию и многое другое.
Вы также можете подписаться на рассылку Django для начинающих для периодических
обновлений нового контента и скидок на будущие книги.
И последний ресурс мой личный сайт, wsvincent.com, который регулярно обновляется и
содержит статьи о некоторых из этих передовых методов:
Группа в ВК "Django_Python"
302
Conclusion
• Django Social Authentication
• Django Login Mega-Tutorial
• Django, PostgreSQL, and Docker
• Django Rest Framework Tutorial
• Django Rest Framework with React
Ресурсы Django
Чтобы продолжить изучение Джанго, я рекомендую работать через следующие бесплатные
онлайн уроки:
• Official Polls Tutorial
• Django Girls Tutorial
• MDN: Django Web Framework
• A Complete Beginner’s Guide to Django
Я также настоятельно рекомендую Two Scoops of Django 1.11: Best Practices for the
Django Web Framework, который является текущей Библией лучших практик для
разработчиков Django.
Книги Python
Если вы новичок в Python, есть несколько отличных книг от начинающих до продвинутых
Pythonistas:
• Python Crash Course это фантастическое введение в Python, которое также
проведет вас через три реальных проекта, включая приложение Django.
• Think Python одновременно вводит в основы Python и информатики.
Группа в ВК "Django_Python"
303
Conclusion
• Automate the Boring Stuff это еще одно отличное руководство по обучению и
использованию Python в реальных условиях.
• The Hitchhiker’s Guide to Python содержит рекомендации по программированию на Python.
• Python Tricks демонстрирует, как писать Python код.
• Effective Python отличное руководство не только по Python, но и по
программированию в целом.
• Fluent Python удивительно и обеспечивает глубокое понимание языка Python.
Блоги
Эти сайты предоставляют регулярные высококачественные статьи по Python и вебразработке.
• Real Python
• Dan Bader
• Trey Hunner
• Full Stack Python
• Ned Batchelder
• Armin Ronacher
• Kenneth Reitz
• Daniel Greenfeld
Обратная связь
Если вы прошли через всю книгу, мне бы очень хотелось услышать ваши мысли. Что тебе
понравилось или не понравилось? Какие области были особенно сложными? А какой
новый контент вы хотели бы видеть? Со мной можно связаться по адресу
will@wsvincent.com.
Группа в ВК "Django_Python"
От переводчика.
Перевод не является профессиональным, прошу сильно не пинать
эта книга мой первый опыт в переводе книг, но я старался
максимально точно передать содержимое на русском языке.
Изначально переводил для себя фрагментами как шпаргалки,
которые позже были собраны воедино. Надеюсь труд автора и мой не
будет напрасным для вас и вы получите необходимые знания.
Вступайте в группу "в контакте" https://vk.com/Python_Django_RU
делитесь своим мнением, обсуждайте и предлагайте новые книги к
переводу.
И если вы можете помочь с переводом других книг не стесняйтесь
предлагать помощь, вместе прогресс будет быстрей.
Группа в ВК "Django_Python"
Download