Академический Документы
Профессиональный Документы
Культура Документы
on,
an о
и Bootstrap
/AII tft.1,utft.1нw.ux
Санкт-Петербург
« БХВ-Петербург»
2023
УДК 004.43
ББК 32.973.26-018.1
П63
Постолит А. В.
П63 Python, Django и Bootstrap для начинающих. - СПб.: БХВ-Петербург,
2023. -624 с.: ил. -(Для начинающих)
ISBN 978-5-9775-1807-9
Книга посвящена вопросам разработки веб-приложений с использованием язы
ка Python, фреймворков Django, Bootstrap и интерактивной среды разработки
PyCharm. Рассмотрены основные технологии и рабочие инструменты создания
веб-приложений. Описаны фреймворки Django, Bootsrtap и структура создаваемых
веб-приложений. На простых примерах показана обработка и маршрутизация за
просов пользователей, формирование ответных веб-страниц. Рассмотрено создание
шаблонов веб-страниц и форм для пользователей. Показано взаимодействие поль
зователей с различными типами баз данных через модели. Описана работа с база
ми данных через встроенные в Django классы без использования SQL-зanpocoв.
Приведен пошаговый пример создания сайта -от его проектирования до форми
рования программных модулей и развертывания сайта в Интернете с базами дан
ных SQLite и MySQL. Электронный архив на сайте издательства содержит коды
всех примеров.
Для программистов
УДК 004.43
ББК 32.973.26-018.1
https://t.me/it_boooks/2
Предисловие ..................................................................................................................... 9
Глава 1. Инструментальные средства для разработки веб-приложений .......... 15
1.1. Интерпретатор Python ............................................................................................................16
1.1.1. Установка Python в Windows.......................................................................................17
1.1.2. Установка Python в Linux ............................................................................................20
1.1.3. Проверка интерпретатора Python................................................................................20
1.2. Интерактивная среда разработки программного кода PyCharm......................................... 21
1.2.1. Установка PyCharm в Windows ................................................................................... 22
1.2.2. Установка PyCharm в Linux .........................................................................................24
1.2.3. Проверка PyCharm .......................................................................................................25
1.3. Установка пакетов в Python с использованием менеджера пакетов pip ............................ 28
1.3.1. Репозиторий пакетов программных средств PyPI ..................................................... 28
1.3.2. pip- менеджер пакетов в Python............................................................................... 29
1.3.3. Использование менеджера пакетов pip ...................................................................... 30
1.4. Фреймворк Django для разработки веб-приложений ........................................................... 31
1.5. Менеджер баз данных SQLiteStudio...................................................................................... 35
1.6. Краткие итоги.......................................................................................................................... 37
Инструментальные средства
для разработки веб-приложений
https://t.me/it_boooks/2
ММ<hJО,ЮЮ
1�•--.i
l'ytfl"1.,.1
На момент написания книги доступен Python версии 3.11, однако здесь мы будем
использовать более раннюю версию 3.8, поскольку она стабильно работает на всех вер
сиях Windows, начиная с Windows 7 и выше.
+ Customize installation
Choose loc1tion •nd fellures
python
t'Qc- Install launcher for all uиrs (remmmended)
windows Add Python 3.8 to РАТН Cancll J
Рис. 1.2. Выбор способа установки Python
• при выборе Install Now Python установится в папку по указанному в окне пути.
Помимо самого интерпретатора будут инсталлированы ШLЕ (интегрированная
среда разработки), pip (пакетный менеджер) и документация, а также созданы со
ответствующие ярлыки и установлены связи (ассоциации) файлов, имеющих
расширение ру, с интерпретатором Python;
• Customize installation - это вариант настраиваемой установки. Опция Add
Python 3.8 to РАТН нужна для того, чтобы появилась возможность запускать
интерпретатор без указания полного пути до исполняемого файла при работе
в командной строке.
3. Отметьте необходимые опции установки, как показано на рис. 1.3 (доступно при
выборе варианта Customize installation).
На этом шаге нам предлагается отметить дополнения, устанавливаемые вместе
с интерпретатором Python. Рекомендуется выбрать как минимум следующие опции:
• Documentation - установка документации;
• pip - установка пакетного менеджера pip;
• tcl/tk and IDLE - установка интегрированной среды разработки (ШLЕ) и биб
лиотеки для построения графического интерфейса (tkinter).
4. На следующем шаге в разделе Advanced Options (дополнительные опции) выберите
место установки, как показано на рис. 1.4 (доступно при выборе варианта Customize
installation).
Помимо указания пути, этот раздел позволяет внести дополнительные изменения
в процесс установки с помощью опций:
• Install for all users - установить для всех пользователей. Если не выбрать эту
опцию, то будет предложен вариант инсталляции в папку пользователя, устанав
ливающего интерпретатор;
Инструментальные средства для разработки веб-приложений 19
Optional Features
Pi Qoёi,mentatiod
lnstails ttw Python doo.lmentation liJe.
"5 gip
!r.s1all$ р,р, which c.;n downloa<I and i/1$!.III oth�r Python p;i�
Р td/\k and IDLE
lnstalls tlcintl!f and the IDlf developmв,t environment.
Р P)tthon 1est suite
tnsta!ls � standJt'd l!Ьrary test wrte.
и Р! ру J;lurк:мr Р fol' 11 US4!l'S (requires l!ll!vation)
lнsta!ls the gioЬ..I 'ру' launcher to maice ,t easier to star1 Pytl1on.
python
windows llc:t !l8t
Advanced Options
J;11 lnsW fot j)I uws
Р Assodatl! files with Python (requires thl! ру laundll!f)
Р CrNte mortcuts for mtatled applications
Р Add Pythotl to tnvirof\ment vari.lbles
i;;; er� standatd lilnry
Г Download deЬugging ,tymЬoJs
Г, Download deЬug Ьinaries (requim VS 2015 or latet1
• Associate files with Python - связать файлы, имеющие расширение ру, с Python.
При выборе этой опции будут внесены изменения в Windows, позволяющие
Python запускать скрипты по двойному щелчку мыши;
• Create shortcuts for installed applications - создать ярлыки для запуска прило
жений;
• Add Python to environment variaЫes - добавить пути до интерпретатора Python
в переменную РАТН;
• Precomple standard library - провести перекомпиляцию стандартной библио
теки.
20 Глава 1
Последние два пункта (см. рис. 1.4) связаны с загрузкой компонентов для отладки,
их мы устанавливать не будем.
5. После установки Python вас ждет следующее сообщение об успешном завершении
установки (рис. 1.5).
с::,
python
fм
windows k aose 1
Рис. 1.5. Финальное сообщение после установки Python
iJ C:\Python38\python.exe 1!!10. )(
Python 3.8.10 <tags/u3.8.10:Зd899Зa. Мау З 2021. 11:48:03) [MSC u.1928 64 bit <
AMD64)] on win32
Туре "}1е111О.. "coi1yt"igl,t" ,. "ct"edit�" 01" "license" fol' rюt"e infot"fflation.
> » pt•int <"Неllo. llot•ld! ")
Hello, llo,•ld!
>»
Download PyCharm
Windows Мае Linvx
Professional Community
Fot Ьoth Sdenьfic and wеь Python Fot pure Pymon deve\opmtnt
Version: 2019.3.4 development With НТМ1.. JS. and $QL
ее+
8uitd: 193.6911.2S support.
18 March 2020
$ystem requirements
Free ttial fr�. o�-source
ln:itallftior) lnsщкtiOl1$
Other versions
t
Рис. 1.9. Начальная заставка при инсталляции PyCharm
Инструментальные средства для разработки веб-приложений 23
Chooиlnd81�
0-the foldef lnwlichtolnst4Py(:harm�Edtlcn.
1rwt......-.Opliar8
Conlloin '°" PyOiann Colmv.ity Edtion instllation
Updeteaiml!Xtll\IOI
�Adcl"Ope,,l'olderesProject'
' .ру
Select the Start Мeriu fillder ill whicn YoU wotAd lke to опtе 1he progrillll\'$ $hortcu\s. You
сап lllso enter а мmе to а9Ь: а,- folder,
7-ц,
Acc:essot;es
Ali'ninistratм! Tools
Celeant!r
Dejr...
Games
K-!.ite Godec Pack
· Мicrosoft Azl.re
Мicrosoft Offlc:e
Мicrosoft SQ'. server 2008
•·
____t_f.№li___l , �
Рис. 1.13. Финальное окно установки пакета PyCharm
Рис. 1.19. Одна строка программного кода на Python в среде разработки PyCharm
Рис. 1.20: Запуск строки программного кода на Python в среде разработки PyCharm
28 Глава 1
· Рис. 1.21. Вывод результатов работы программы на Python в среде разработки PyCharm
S Выполнить х
Beeдirre 11м• nроrр1мм1,1, nanщ доtеуt.tента ми pecyrx:a
"'
Интернет� которые требуется от�срыть.
Открыть:
+
!
� Т erminal: Loc1JI
�1icro�oft hindo\,'S [Vf'!��ion 10.0.17134.1304)
,-.., ::t:.) t-:српорац ..,� r,a.iikpccoфт (F•',icro!.oft Cor--po�ation) .• 2018. Все права :з.ащищены.
*
► � Run •= !i тооо 13 Termtnal + Python Consolt
о
Рис. 1.25. Выполнение команды модуля pip в терминальном окне PyCharm
Откроется окно, где вы можете задать имя создаваемому проекту, определить вирту
альное окружение для этого проекта и указать каталог, в котором находится интерпре
татор Python. Задайте новому проекту имя wеь_1 и нажмите кнопку Create (рис. 1.27).
Рис. 1.27. Задаем новому проекту имя Web_ 1 в среде разработки PyCharm
Будет создан новый проект. Это, по сути дела, шаблон проекта, в котором пока еще
ничего нет (рис. 1.28).
Фреймворк Django - это фактически дополнительная библиотека к Python, и устано
вить данный инструментарий можно так же, как и любую другую библиотеку. Для
установки библиотеки Django можно в меню File выбрать опцию Settings... (рис. 1.29).
В левой части открывшегося окна настроек выберите опцию Project Interpreter,
и в правой части окна будет показана информация об интерпретаторе языка Python и
подключенных к нему библиотеках (рис. 1.30).
Инструментальные средства для разработки веб-приложений 33
Чтобы добавить новую библиотеку, нужно нажать на значок в правой части окна,
после чего будет отображен полный список доступных библиотек. Здесь можно либо
пролистать весь список и найти библиотеку Django, либо набрать наименование этой
библиотеки в верхней строке поиска, и она будет найдена в списке (рис. 1.31).
Дolpo-•-.�-sc;JJt1511do.
W'1М
1 завершить !
Рис. 1.34. Завершающее окно установки менеджера SQLiteStudio
з
Ple4Sedloose�:
О1С
Са1О!1 1
Рис. 1.35. Окно выбора языка интерфейса менеджера SQLiteStudio
Database
Ба3Ы данных 6 Х
i�льтрnои.
Как можно видеть, несмотря на выбор русского языка в окне выбора языка интерфейса
(см. рис. 1.35), меню в главном окне менеджера SQLiteStudio выведено в англоязычном
исполнении. Это, скорее всего, не совсем корректная локализация именно данной вер
сии программного продукта - часть интерфейса осталась нелокализованной.
Веб-технологии
и базовые сведения об HTML
В настоящее время веб-технологии стремительно развиваются, проникая в самые раз
нообразные сферы нашей жизни. Для компаний присутствие в сети Интернет - это
возможность рассказать о своих товарах и услугах, найти потенциальных партнеров
и клиентов, снизить издержки за счет интернет-торговли и «облачных» сервисов. Ря
довые пользователи уже привыкли к услугам интернет-магазинов, интернет-банкинга,
общаются в социальных сетях, могут получать через Интернет государственные
услуги.
Из материалов этой главы вы также узнаете:
□ что такое веб-технологии;
□ в чем различия технологий клиентского и серверного программирования;
□ какие фреймворки предназначены для создания веб-приложений на Python;
□ какие теги помогут представить текст на НТМL-страницах;
□ что такое каскадные таблицы стилей;
□ какие возможности таит в себе скриптовый язык JavaScript.
Сайт
Клиент Сервер
Такая схема приемлема �з том случае, когда содержимое сайта довольно постоянно и
изменяется сравнительно редко. Если же информация, размещенная на статическом
сайте, требует регулярной актуализации и обновления, то для его поддержания неиз
бежны внушительные трудозатраты. Таким образом, статический сайт дешевле в раз
работке,,,и технической поддержке, но эти достоинства могут нивелироваться серьезны
ми не96статками, связанными с необходимостью оперативного обновления актуальной
инфо�мации и достаточно высокой трудоемкостью модификации.
Динамический сайт - это сайт с динамическим информационным наполнением.
Динамические страницы также формируются с помощью НТМL, но такие страницы
обновляются постоянно, нередко при каждом новом обращении к ним. Динамические
сайты основываются на статических данных и НТМL-разметке, но дополнительно со
держат программную часть (скрипты), а также базу данных (БД), благодаря которым
страница «собирается» из_ отдельных фрагментов в режиме реального времени. Это по-
Веб-технологии и базовые сведения об HTML 41
Сайт
Сервер
Клиент
Данные
Шабпон
Дикамичеаwr вю-страюща
Динамичность сайта закточается в том, что для изменения страницы достаточно поме
нять ее информационное наполнение, а сам механизм формирования и вывода страни
цы остается тем же. Кроме получения различных данных, удаленный клиент может
изменить и содержание информационной части сайта. Для этого используются веб
формы. Клиент заполняет веб-форму своими данными, и эта информация вносится
в БД сайта.
Динамические сайты различаются в зависимости от применяемых технологий и про
цесса получения динамических страниц. Динамические страницы можно получить сле
дующими способами:
□ генерацией страницы на стороне сервера, осуществляемой серверными скриптами
на языках РНР, Perl, ASP.NET, Java, Python и др. При этом информационное напол
нение страниц хранится в базах данных;
□ генерацией страницы на стороне клиента (JavaScript);
□ комбинированной генерацией. Чаще всего на практике встречается именно комби
нация первых двух способов.
------------
Full Stack Web Development
Back End
F ront End
1
Клиентская часть Серверная часть
._.
□ .... □
1
SQL
Server
Php, Asp.net SQL Server, Oracle,
HTML, CSS, JavaScript Java, Node JS, Му SQL, SQLite
python PoatgreSQL
Вootstrap Ojango
Рис. 2.3. Структура веб-приложения с фреймворками Django и Bootstrap
<html>
<head>
СОДЕРЖАНИЕ ЗАГОЛОВКА ДОКУМЕНТА
</head>
46 Глава 2
<body>
СОДЕРЖАНИЕ ТЕЛА ДОКУМЕНТА
</body>
</html>
Заголовок может включать в себя несколько специализированных тегов, основными из
которых являются <title> ... </title> и <rneta>...</meta>.
Тег <title> содержит информацию, которая будет вьшодиться в заголовочной части
окна браузера пользователя. Например, если в этом теге имеется текст
<title>Миp книг</titlе>
то он отобразится в окне браузера так, как показано на рис. 2.4.
ф 127.0.0.1:8000
<!DOCTYPE HTML>
<html>
<head>
<title>Beб-cтpaницa</title>
<meta charset=windows-1251">
<meta name="keywords" соntеnt="веб-страница первая">
</head>
<Ьоdу>
Моя первая веб-страница
</body>
</html>
Тег <НR>- предназначен для вьmода горизонтальной линии. Параметр align этого тега
определяет выравнивание линии относительно одной из сторон документа. Этот тег
имеет еще несколько параметров:
□ size - высота
линии;
□ width - ширина линии;
□ color - цвет линии;
□ noshade - отключает отбрасывание тени.
Представленные далее теги меняют следующие параметры текста:
□ <В> - полужирный текст;
□ <I> - наклонный текст;
□ <U> - подчеркнутый текст;
□ <ТТ> - моноширинный текст.
Тег <PRE> - выводит заранее отформатированный текст. Используется он для того,
чтобы текст с пробелами, символами перехода на новые строки и символами табуляции
корректно отображался браузером. В секциях <PRE> могут присутствовать гипертексто
вые ссылки, однако применять другие НТМL-теги нельзя.
Тег <R:m'> - задает некоторые свойства шрифта. Эти свойства определяются следую
щими параметрами:
□ size - размер шрифта от 1 до 7;
□ face - начертание шрифта;
□ color - цвет шрифта.
В листинге 2.3 приведен пример использования некоторых тегов.
ПРИМЕЧАНИЕ
В НТМL-коде цвет определяется 6-значным кодом RRGGBB (красный, красный, зеленый,
зеленый, синий, синий), а в JavaScript или в CSS таким же 6-значным кодом или английским
названием цвета. Со значениями кодов, обозначающих цвета, можно ознакомиться по сле
дующей ссылке: https:/lwww.rapidtaЫes.com/weЫcolor/html-color-codes.html.
2.2.2. Списки
Современным стандартом НТМL предусмотрены три основных вида списков:
□ маркированные списки (unordered list);
□ нумерованные списки (ordered list);
□ списки определений (definition list).
Маркированные списки названы так потому, что перед каждым пунктом таких списков
устанавливается тот или иной маркер. Иногда, прибегая к дословному переводу, их
также назьmают неупорядоченными списками (unordered list). Маркированные списки
50 Глава 2
задаются при помощи тегов <ul> ...<ul>. Для задания элементов списка (item list) ис
пользуются теги <il> ...</il>. Например:
<ul>
<li>Пункт l</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
</ul>
Помимо элементов списка внутри тегов <ul> ...<ul> можно размещать и другие теги -
например, теги заголовков:
<ul>
<hЗ>Маркированный список</hЗ>
<li>Пункт l</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
</ul>
Тип маркера можно задавать с помощью атрибута type. Три его возможных значения:
□ circle (незакрашенный кружок);
□ ctisk (закрашенный кружок);
□ square (закрашенный квадрат).
По умолчанию задан тип ctisk. Следует отметить, что различные модели браузеров
могут по-разному отображать маркеры. Вот пример использования маркера типа circle:
<ul type="circle">
<li>Пункт l</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
</ul>
В нумерованных списках (ordered list), которые иногда назьmают упорядоченными, каж
дому пункту присваивается номер. Создаются такие списки при помощи тегов
<ol> ... </ol>. Для элементов нумерованных списков, как и в случае маркированных спи
сков, также используются теги <il> ...</il>. В таких списках, как и в маркированных,
доступны пять типов маркеров, определяемых при помощи атрибута type, который
может принимать следующие значения:
□ 1 - арабские цифры;
□ i - строчные римские цифры;
□ r - прописные римские цифры;
□ а - строчные латинские буквы;
□ А - прописные латинские буквы.
Далее приведены примеры нумерованных списков:
<ol>
<hЗ>Нумерованный список</hЗ>
<li>Пункт l</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
</ol>
Веб-технологии и базовые сведения об HTML 51
<ol type="I">
<li>Пункт l</li>
<li>Пункт 2</li>
<li>Пункт 3</li>
</ol>
Списки определений (defmition list) предназначены для того, чтобы организовать текст
по примеру словарных статей. Они задаются с помощью тегов <dl> ...</dl>, а опреде
ляемый термин или понятие (definition term) помещается в теги <dt> ... </dt>.
Определение понятия (definition description) заключается в теги <dd> ...</dd>. В тексте,
содержащемся внутри тегов <dt> ...</dt>, недопустимы теги уровня блока, такие как <р>
или <div>. Как и в предыдущих случаях, внутри списков определений могут быть теги
заголовков и прочие теги:
<dl>
<hЗ>Список определений</hЗ>
<dt>Понятие l</dt>
<dd>Определение понятия l</dd>
<dt>Понятие 2</dt>
<dd>Определение понятия 2</dd>
</dl>
Как маркированные, так и нумерованные списки можно вкладьmать друг в друга, при
чем допускается произвольное вложение различных типов списков. При вложении друг
в друга маркированных и нумерованных списков следует быть внимательным. В лис
тинге 2.4 приведен пример вложенных списков.
<ul>
<hЗ>Пример вложенных списков</hЗ>
<li>Пункт l</li>
<ol>
<li>Пункт 1.1</li>
<li>Пункт 1.2</li>
</ol>
<li>Пункт 2</li>
<ol type="i">
<li>Пункт 2.1</li>
<li>Пункт 2.2</li>
<li>Пункт 2.3</li>
</ol>
<li>Пункт 3</li>
<ol type="I">
<li>Пункт 3.1</li>
</ol>
</ul>
2.2.3. Таблицы
Таблицы - один из основных элементов, предназначенных для структурирования
информации в НТМL-документах. Хотя сейчас такое использование таблиц признано
52 Глава 2
<td>l.2</td>
<td>l.3</td>
</tr>
<tr align="center">
<td align="center">2.1</td>
<td align="right">2.2</td>
<td>2.3</td>
</tr>
</tаЫе>
логотип
� мод,удьноi с.-пи
3агопоl01( аАта
OOiollffOA ДоnоnкнтеJ1ькые
Меню
материал функцнн
Ококчанне cam
</div>
Этот тег имеет ряд атрибутов:
□ align="пapaмeтp"- задает выравнивание;
□ сlаss="имя"- определяет принадлежность к классу;
□ stуlе="стили через запятую"- задает стили;
□ title="тeкcт"- задает вспльmающая подсказка к тегу.
Атрибут align (выравнивание) может принимать следующие значения:
□ center- выравнивание текста по центру;
□ left- выравнивание текста по левому краю;
□ right- выравнивание текста по правому краю;
□ justify- выравнивание по ширине.
В листинге 2.8 приведен пример использования тега <ctiv>.
<html>
<head>
<style type="text/css">
.center {
text-align: center;
}
</style>
</head>
<body>
<div class="center">
Этот текст будет выровнен по центру
</div>
56 Глава 2
</body>
</html>
В данном примере текст, заключенный в тег <ctiv>, будет выровнен по центру страницы.
Более детально использование этого тега будет показано на примерах в разделе, посвя
щенном фреймворку Bootstrap.
2.2.5. Гиперссылки
Для связи различных документов НТМL предусматривает использование ссылок. Сам
термин НТМL (Hyper Text Markup Language) подразумевает их широкое применение.
Для реализации ссьшок в НТМL служит тег <а> ...</а>, который, как и большинство
НТМL-тегов, является контейнерным. Основной атрибут этого тега - href, собственно
и содержащий адрес ресурса, на который указывает ссьшка. Внутри тега <а> ...</а>
помещается текст ссылки.
В ссьшках возможна как относительная, так и абсолютная адресация. При абсолютной
адресации атрибуту href присваивается абсолютный URL-aдpec ресурса:
<а href ="http://server.com/doc3.htm">Ccылкa на документ с абсолютным адресом
http://server.com/doc3.htm</a>
При относительной адресации указывается путь к документу относительно текущей
страницы:
<а href ="docl.htm">Ccылкa на документ с относительным адресом docl.htm</a>
Если в заголовочной части документа указан тег <Ьаsе>, то отсчет будет вестись от ад
реса, заключенного в этом теге.
Помимо веб-страниц, допускается ссьшаться и на другие интернет-ресурсы: e-mail, ftp,
Ghofe, WAIS, Telnet, newsgroup. Далее приведен пример ссьшки на адрес электронной
почты:
<а href="mailto:sss@mail.ru">Ccылкa на адрес электронной почты sss@mail.ru</a>
В роли ссьшок могут выступать и рисунки. Для этого сначала нужно вставить рисунок
с помощью тега <img>. У атрибута src этого тега устанавливается значение, соответст
вующее имени файла рисунка:
<img src="figl.jpg">
Далее, рисунок "обертывается" в тег ссьшки:
<а href="link2.htm"><img src="figl.jpg" border="O"></a>
Для того чтобы таблица стилей влияла на вид НТМL-документа, она должна быть под
ключена к нему. Подключить каскадные таблицы стилей можно с использованием
внешних, внутренних или локальных таблиц стилей:
□ внешние таблицы стилей, оформленные в виде отдельных файлов, подключаются
к НТМL-документу при помощи тега в заголовке документа. Например:
<LINK rel="stylesheet" href="style.css" type= "text/css">
Этот способ обычно применяется для сценариев большого размера или сценариев, мно
гократно используемых на разных неб-страницах.
Можно подключать JavaScript к обработчику события. Дело в том, что каждый НТМL
элемент может иметь JavaScript-coбытия, которые срабатывают в определенный мо
мент. Нужно добавить необходимое событие в НТМL-элемент как атрибут, а в качестве
значения этого атрибута указать требуемую функцию. Функция, вызьmаемая в ответ на
срабатьmание события, и станет обраб9тчиком события. В результате срабатывания
события исполнится связанный с ним код. Этот способ применяется в основном для
коротких сценариев - например, можно установить смену цвета фона при нажатии на
кнопку (листинг 2.9).
<script>
var colorArray = ["#5А9С6Е", "#A8BF5A", "#FAC46E", "#FADSBB",
"#F2FEFF"]; // создаем массив с цветами фона
var i = О;
60 Глава 2
function changeColor() {
document.body.style.background = colorArray[i];
i++;
if( i > colorArray.length - 1) {
i = О;
</script>
<button onclick="changeColor();">CМeнить цвет фoнa</button>
Код внутри элемента <script> можно вставлять в любое место документа. Код, который
выполняется сразу после прочтения браузером или содержит описание функции, кото
рая выполняется в момент ее вызова, располагается внутри тега. Описание функции
можно располагать в любом месте - главное, чтобы к моменту ее вызова код функции
уже был загружен.
Обычно код JavaScript размещается в заголовке документа (в элементе <heact>) или по
сле открывающего тега <body>. Если скрипт используется после загрузки страницы (на
пример, код счетчика), то его лучше разместить в конце документа:
<footer>
<script>
document.write("Bвeдитe свое имя");
</script>
</footer>
</body>
Макетирование НТМL-страниц
с фреймворком Bootstrap
Фреймворк Bootstrap позволяет ускорить процесс верстки НТМL-страниц и сделать
готовый продукт адаптивным к разным вариантам разрешения и формата экрана. Он
распространяется бесплатно в виде файлов формата НТМL, CSS и JS. Это один из
самых популярных фреймворков в мире. Основная область применения - разработка
интерфейса сайтов, веб-приложений и среды администрирования. Любому веб-раз
работчику необходимо знать хотя бы базовые сведения об этом фреймворке и исполь
зовать его в своей работе.
Из материалов данной главы вы узнаете:
□ о технологиях, заложенных в основу Bootstrap;
□ как можно получить файлы фреймворка Bootstrap;
□ что такое контейнеры и сетка Bootstrap;
□ как можно сверстать макет НТМL-страниц;
□ как подключить файлы фреймворка Bootstrap к проекту;
□ как задать цвет элементам НТМL-страниц;
□ как задать отступы в элементах макета НТМL-страниц;
□ как выровнять содержимое в адаптивных блоках НТМL-страниц;
□ как можно обозначить границы элементов в макете НТМL-страниц;
□ как использовать адаптивные контейнеры при макетировании НТМL-страниц.
</body>
/html>
Здесь в теге <head> заголовка сайта присутствует пять строчек. Первые две строки не
имеют отношения в Bootstrap, но для начинающих изучать основы веб-програм
мирования поясним их назначение. Тег <title> служит для вьmода информации, кото
рая появится на самой верхней вкладке интернет-браузера. Далее следуют две строки
с метатегами, разберемся, что это за теги <meta> и для чего они нужны.
Тег <meta> (от англ. meta infonnation - метаинформация) определяет данные, которые
предназначены для браузеров и поисковых систем. Например, механизмы поисковых
систем обращаются к метатегам для получения описания сайта, ключевых слов и дру
гих данных. Разрешается использовать более чем один метатег, все они размещаются
в заголовке НТМL-страницы - в теге <head>.
Метатег <meta charset="UTF-8"> определяет кодировку символов, которая будет принята
на сайте. В приведенном ранее коде тег означает, что на сайте будет использоваться
8-битовый формат преобразования Unicode, который является стандартной кодировкой
символов в последней версии НТМL 5. Эта строка должна быть включена в каждую
созданную веб-страницу, т. к. она гарантирует правильное отображение символов лю
бого языка в любом браузере. Кодировка UTF-8 гарантирует, что символы нелатинских
языков не будут искажаться. Браузер Google Chrome автоматически установил коди
ровку UTF-8, поэтому вам не придется беспокоиться об этом при разработке дизайна
для этого браузера. Но вам все равно нужно включать <meta charset="UTF-8"> в каждый
файл НТМL на случай, если эта функция не поддерживается другими браузерами.
Метатег <namв="viewport"> определяет, как нужно настроить параметры окна браузера
для конкретного устройства, особенно это актуально для мобильного телефона. В на
стоящее время важно, чтобы веб-страницы хорошо отображались на всех устройствах:
на настольных компьютерах, ноутбуках, планшетах и особенно на мобильных телефо
нах. Для этого нужно включить метатег <name="viewport"> в каждый файл НТМL. Этот
тег определяет, как страницы сайта будут отображаться на экранах разного размера и
Макетирование НТМL-страниц с фреймворком Bootstrap 65
Эта информация показьmает, кто является владельцем веб-сайта или кому принадлежат
авторские права.
Скачивание файлов Bootstrap. Второй путь использования фреймворка Bootstrap -
скачать готовые файлы и подключить их к своему приложению. Этот путь тоже не
представляет особых трудностей. Скачать готовые файлы можно с официального сайта
по следующей ссьшке: https://getbootstrap.com/docs/5.2/getting-started/download/.
После скачивания вы получите архивированный ziр-файл, в имени которого будет от
ражена текущая версия фреймворка, например bootstrap-5.2.3-dist.zip. После распаковки
архива будут созданы две папки: css - с файлами стилей и js - с jаvа-скриптами. Эти
две папки нужно перенести в ваш проект.
66 Глава 3
c:::Jxx111----+
Extra large
r;::J., lg 111
1Л
а..
Medium I:::.J.. - q
a..
ь
А1
.'1
Omd о
о
■■L-----------...."
d)
a
о
S
о
m ll Sm -
,:Q
X- m�
S
□---------..... �� �
Рис. 3.1. Контрольные точки для Bootstrap 4 и Bootstrap 5
Цифры на этом рисунке означают, что при ширине видимой области браузера до 576 рх
макет сайта будет отображаться одним образом, от 576 до 768 рх - другим образом
и т. д. Иными словами, можно создать макет, который на каждом из этих участков
видимой области браузера станет выглядеть по-разному.
Контрольные точки (breakpoint) имеют обозначение. Первая контрольная точка не име
ет обозначения (т. е. xs не указьmается), вторая обозначается - sm, третья - m::1, четвер
тая - lg, пятая - xl и шестая - xxl. Эти обозначения необходимо запомнить, т. к. они
используются в классах, которые мы будем добавлять к элементам. Эти обозначения
в имени класса будут указьmать на то, с какой ширины viewport стили, определенные
Макетирование НТМL-страниц с фреймворком Bootstrap 67
в нем, будут применяться к вложенным элементам. При этом контрольные точки зада
ют только минимальную ширину. Например, если вы определили макет, указав в нем
классы без обозначения контрольной точки (xs) и с использованием параметра пю, то на
устройстве sm страница будет иметь такую же структуру, как и на устройстве xs, а на
устройствах с большим экраном lg, xl и xll - как на rnd.
Теперь разберемся с сеткой НТМL-страницы в Bootstrap. Сетка состоит из следующих
элементов:
□ оберточных контейнеров (элементов с классом container, container-fluid, или
container-{breakpoint));
□ рядов или строк (элементов с классом row);
□ адаптивных колонок или блоков, имеющих один или несколько классов col.
Все части сетки - это обычные элементы НТМL, к которым просто добавлены опреде
ленные классы.
Оберточный контейнер
, . --·--дaa-nm�fJнo-- 8
фuксuроfJанныu
конmеuнер
фuксuроfiанная шuрuна
на sm, md, lg, xl, xxl
В Bootstrap ряды играют очень важную роль. Это связано с тем, что сетка НТМL
страниц построена на CSS Flexbox - адаптивных блоках. В этой сетке ряд выступает
в роли flех-контейнера для flех-элементов (адаптивных блоков). Если адаптивные бло
ки окажутся вне ряда, то они работать не будут, в Bootstrap адаптивные блоки ДОЛЖНЫ
обязательно находиться в блоке с классом row. Компенсация внутренних отступов
(padding) осуществляется за счет отрицательных левых и правых внешних отступов,
равных 15 рх (margin-left:-15px и margin-right:-15px).
тейнера). Например, адаптивный блок в браузере смартфона (sm) может иметь ширину,
равную 50% от родительского элемента, а на планшете (mci) - 25%.
Адаптивный блок достаточно просто создать посредством добавления одного или не
скольких классов col-?-? к НТМL-элементу, расположенному в ряду. В классе col-?-?
вместо первого знака вопроса указывается название контрольной точки («пусто», sm, md,
lg, xl или xxl). Вместо второго знака вопроса задается ширина адаптивного блока, кото
рую он должен иметь на указанной контрольной точке. Ширина адаптивного блока на
значается в относительной форме либо по умолчанию, либо с помощью числа от 1
до 12 (по количеству колонок).
Число, которое стоит при ищщиализации класса col, определяет, какую часть ширины
родительского контейнера (т. е. ряда) будет занимать адаптивный блок, начиная с ука
занной контрольной точки. При этом ширина ряда в числовом выражении (в колонках
Bootstrap) по умолчанию равна 12. Например, блок с классом col-md-4, начиная с кон
трольной точки md, будет занимать 4/12 ширины ряда, т. е. 4/12-100% = 33,3%.
Адаптивные блоки, как и оберточные контейнеры, имеют внутренние отступы слева и
справа по 15 рх. Данные отступы адаптивным блокам во фреймворке Bootstrap устанав
ливаюrся с помощью CSS свойств padding-left: 15рх и padding-right: 15рх. Размещать
адаптивные блоки необходимо в ряду (в строке), т. е. у любого адаптивного блока
в качестве родителя должен быть обязательно элемент row.
Рассмотрим на примерах, какую ширину будут иметь следующие адаптивные блоки.
1. class="col-12" задает ширину блока по умолчанию. Ширина блока будет равна
12 колонкам Bootstrap (т. е. 12/12-100% = 100% от ширины ряда), эту ширину блок
будет иметь, начиная с контрольной точки xs.
2. class="col-sm-9" задает ширину блока с контрольной точки sm. Ширина блока будет
равна 9 колонкам Bootstrap (т. е. 9/12-100% = 75% от ширины ряда), эту ширину
блок будет иметь, начиная с контрольной точки sm.
3. class="col-md-7" задает ширину блока с контрольной точки md. Ширина блока будет
равна 7 колонкам Bootstrap (т. е. 7/12· 100% = 58,3% от ширины ряда), начиная с кон
трольной точки md.
Макетирование НТМL-страниц с фреймворком Bootstrap 71
4. class="col-lg-5" задает ширину блока с контрольной точки lg. Ширина блока будет
равна 5 колонкам Bootstrap (т. е. 5/12·100% = 41,6% от ширины ряда), начиная с кон
трольной точки lg.
5. class="col-xl-3" задает ширину блока с контрольной точки xl. Ширина блока будет
равна 3 колонкам Bootstrap (т. е. 3/12·100% = 25% от ширины ряда), начиная с кон
трольной точки xl.
6. class="col-xxl-6" задает ширину блока с контрольной точки больше xxl. Ширина
блока будет равна 2 колонкам Bootstrap (т. е. 6/12-100% = 50% от ширины ряда).
При задании ширины адаптивному блоку мы указьmаем класс, содержащий контроль
ную точку, начиная с которой данная ширина будет действовать. Эту ширину данный
блок будет иметь до тех пор, пока она не будет переопределена с помощью другого
класса, действие которого начинается с наибольшей ширины viewport.
Colt Col2 Со1 3 Col 4 Со1 5 Со1 6 Со1 7 Со1 8 Col 9 ColIO Col 11 Col 12
Col 6 Col 6
Col 8 Со1 4
С,о1 ю Col 2
Col 4 Со/ 8
Col 2 Col 10
По умолчанию адаптивные блоки занимают всю высоту ряда, в котором они располо
жены. Выравнивание какого-то определенного адаптивного блока по вертикали в пре
делах ряда может осуществляться одним из следующих классов:
□ align-self-start - выравнивание относительно начала ряда (по верху ряда);
□ align-self-center - по центру ряда;
□ align-self-end- относительно конца ряда (по низу ряда).
Данные классы необходимо добавлять к адаптивным блокам, а не к ряду. Например,
выравниваем адаптивный блок 2 по нижнему краю ряда:
<div class="row align-iterns-center">
<div class="col">Блoк l</div>
<div class="col align-self-end">Блoк 2</div>
</div>
<div class="row">
<div class="col-4">Блoк 1</div>
<div class="col-4 offset-4">Блoк 1</div>
</div>
<div class="row">
<div class="col-3 оffsеt-З">Блок З </div>
<div class="col-3 оffsеt-З">Блок 4</div>
</div>
<div ·class="row">
<div class="col-6 оffsеt-З">Блок 5</div>
</div>
В этом случае смещение адаптивных блоков будет выглядеть так, как показано на
рис. 3.8.
uС.' � Pro_1ect • €) (1 -
..
� • 111 Boot Start
Рис. 3.1 О. Структура папок
т 118static проекта Boot_Start
► 111 с»
► IIIJI
► 111 v·env
► 11111 External L1brar1e
.. -�!70 5cri!tches and С onsoles
Чтобы процесс создания макетов страниц был более понятен, разберем несколько про
стых примеров. Для начала создадим контейнер фиксированной ширины с одним рядом
(строкой), в котором находится один адаптивный блок из 12 колонок, т. е. он будет
занимать всю ширину ряда (листинг 3.1, страница start1.html).
<!DOCTYPE html>
<html lang="en">
<head>
<title>startl</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
76 Глава 3
<body>
<div class="container">
<div class="row">
<div class="col">
<hl>Это страница Bootstrap</hl>
<р>На странице создан контейнер фиксированной ширины
class="container".</p>
<р>В контейнер вложена одна строка class="row."</p>
<р>В строке нахьдится один адаптивный блок class="col".</p>
<р>С изменением размера окна браузера ширина элементов
контейнера будет меняться в разных контрольных точках.</р>
</div>
</div>
</div>
</body>
</html>
При минимальном размере окна браузера данная страница будет выглядеть как на
рис. 3.11.
с::, @] �
0 startl + .V
<!DOCTYPE html>
<html lang="en">
<head>
<titl�>color_bg</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">Пepвaя cтpoкa</div>
<div class="row">
<div class="col bg-primary">Блoк l</div>
<div class="col bg-secondary">Блoк 2</div>
<div class="col bg-success">Блoк 3</div>
<div class="col bg-danger">Блoк 4</div>
<div class="col bg-warning">Блoк 5</div>
<div class="col bg-info">Блoк 6</div>
<div class="col bg-light">Блoк 7</div>
<div class="col bg-dark">Блoк 8</div>
<div class="col bg-white">Блoк 9</div>
</div>
</div>
</body>
</html>
В окне браузера данная страница будет иметь вид, представленный на рис. 3.12.
Как видно из рис. 3.12, текст «Блок 8» не виден, т. к. и шрифт, и фон имеют одинако
вый (черный) цвет.
78 Глава 3
6 @) �
0 color_Ьg
f- ➔ С (Ф Файл 1
� Авиабилеты О Яндекс Qrj Перевести G Gmail
Первая строка
Блок Блок
7 9
Пример НТМL-кода страницы, в которой показано использование класса text для зада
ния цвета шрифту, приведен в листинге 3.3, страница color-text.html.
<!ООСТУРЕ html>
<html lang="en">
<head>
<title>colorl text</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min .css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">Пepвaя cтpoкa</div>
<div class="row">
<div class="col text-primary">Блoк l</div>
<div class="col text-secondary">Блoк 2</div>
<div class="col text-success">Блoк 3</div>
<div class="col text-danger">Блoк 4</div>
<div class="col text-warning">Блoк 5</div>
<div class="col text-info">Блoк 6</div>
<div class="col text-light">Блoк 7</div>
<div class="col text-dark">Блoк 8</div>
<div class="col text-muted">Блoк 9</div>
<div class="col text-white">Блoк 10</div>
</div>
Макетирование НТМL-страниц с фреймворком Bootstrap 79
</div>
</body>
</html>
В окне браузера данная страница будет иметь вид, представленный на рис. 3 .13.
0 color_text
Первая строка
Блок Блок Блок Блок Блок Блок Блок Блок
1 2 3 4 5 6 8 9
Как видно из данного рисунка, текст «Блок 7» и «Блок 10» не виден, т. к. и шрифт,
и фон имеют одинаковый цвет.
Для того чтобы текст всегда был виден, он должен иметь цвет, отличный от цвета фона.
Пример НТМL-кода страницы, в которой показано использование двух классов text
и bg для одновременного задания цвета для шрифта и для фона, приведен в листин
ге 3.4, страница color_text_bg.html.
<!DOCTYPE html>
<html lang="en">
<head>
<title>color_text_bg</title>
<meta charset="UTF-8">
<meta narne="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<div class="row">Пepвaя cтpoкa</div>
<div class="row">
<div class="col text-primary bg-info">Блoкl</div>
<div class="col text-secondary">Блoк2</div>
<div class="col text-success bg-info">БлoкЗ</div>
<div class="col text-danger">Блoк4</div>
<div class="col text-warning bg-info">Блoк5</div>
<div class="col text-info">Блoкб</div>
<div class="col text-light bg-primary">Блoк7</div>
<div class="col text-dark">БлoкB</div>
80 Глава 3
В окне браузера данная страница будет иметь вид, представленный на рис. 3.14. Теперь
текст .во всех блоках стал видимым.
0 color_text_Ьg х +
*
V
Первая строка
- Блок2 - Блок4 44/А Блокб •iMM Блок.В БлокlО
Рис. 3.14. Использование классов text и bg для задания цвета тексту и фону
f Rllcmaa'U Ctpaнмцa.-ce_t.html
<!DOCTYPE html>
<html lang="en">
<head>
<title>space_l</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<div class="row bg-success text-white">Пepвaя cтpoкa</div>
<div class="row">
<div class="col mx-2 bg-primary text-white">Блoк 1</div>
<div class="col mx-2 bg-prirrary text-white">Блoк 2</div>
<div class="col mx-2 bg-prirrary text-white">Блoк 3</div>
</div>
</div>
</body>
</html>
82 Глава 3
Здесь для адаптивных блоков были вставлены горизонтальные отступы в две позиции
(mx-2). В окне браузера данная страница будет иметь вид, представленный на рис. 3.15.
Как видно из данного рисунка, между адаптивными блоками появились горизонталь
ные отступы, однако между рядами (строками) нет разрьmов, и они вплотную примы
кают друг к другу. Исправим это и вставим отступы между рядами (листинг 3.6, стра
ница space_2.html).
+
*
0 spa,:e_l х V
<
<!DOCTYPE html>
<htrnl lang="en">
<head>
<title>space_2</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class= "container">
<div class="row bg-success text-white">Пepвaя cтpoкa</div>
<div class="row my-2">
<div class="col mx-2 bg-primary text-white">Блoк l</div>
<div class="col mx-2 bg-primary text-white">Блoк 2</div>
<div class="col mx-2 bg-primary text-white">Блoк 3</div>
</div>
</div>
</body>
</html>
Здесь для второго ряда бьm вставлен вертикальный отступ в две позиции (my-2). В окне
браузера эта страница будет иметь вид, представленный на рис. 3.16.
Как видно из данного рисунка, между рядами появился вертикальный отступ.
Теперь посмотрим, как можно создать отступы внутри элемента. Пример НТМL-кода
страницы, в которой показано использование отступов в теле адаптивных блоков, при
веден в листинге 3.7, страница space_3.html.
Макетирование НТМL-страниц с фреймворком Bootstrap 83
=
+
@) �
*
0 space_2 х V
Первая строка
<!DOCTYPE htпй>
<htпй lang="en">
<head>
<title>space_З</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container">
<div class="row bg-success text-white">Пepвaя cтpoкa</div>
<div class= "row my-2">
<div class="col mx-2 ру-5 bg-primary text-white">Блoк 1</div>
<div class="col mx-2 ру-5 bg-primary text-white">Блoк 2</div>
<div class="col mx-2 ру-5 bg-primary text-white">Блoк 3</div>
</div>
</div>
</body>
</htпй>
0 space_3 х + V
Первая строка
Здесь для адаптивных блоков бьmи вставлены горизонтальные отступы в две позиции
(mx-2) и внутренний вертикальный отступ (между текстом и внешней границей) в пять
позиций (ру-5). В окне браузера данная страница будет иметь вид, представленный на
рис. 3.17.
Как видно из рис. 3.17, между текстом внутри адаптивных блоков и их внешней грани
цей появились отступы. Обратите внимание, что на всех этих НТМL-страницах текст
внутри адаптивных блоков по умолчанию прижимается к левому краю, т. е. к началу
блока. Разберемся теперь, как можно выравнивать содержимое блоков НТМL-страниц.
<!ООСТУРЕ html>
<html lang="en">
<head>
<title>alignment_l</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container text-center">
<div class="row bg-success text-white">
<div class="col">Блoк в первой cтpoкe</div>
</div>
<div class="row my-2 text-white">
<div class="col mx-2 bg-primary">Блoк 1</div>
<div class="col mx-2 bg-primary">Блoк 2</div>
<div class="col mx-2 bg-primary">Блoк 3</div>
</div>
Макетирование НТМL-страниц с фреймворком Bootstrap 85
</div>
</body>
</htrnl>
с:, @) �
0
*
alignment_l V
� ➔ с Ф Файл 1 C:/Users/Anatoly/PycharmProje... 1В □ �
� Авиабилетъ, О Янд�кс � Пере.вести G Gmail
Как видно из рис. 3.18, во всех дочерних элементах контейнера текст бьm выровнен по
центру адаптивного блока.
Немного изменим код этого примера и во втором ряду поменяем параметры выравни
вания текста (листинг 3.9, страница aligment_2.html).
0 alignment_2 х + V
□ L_JI
Рис. 3.20. Различные варианты обозначения границы элемента
□ class="border border-4";
□ class="border border-5".
Пример НТМL-кода страницы, в которой показано создание границ вокруг адаптивных
блоков, приведен в листинге 3.10, страница border_l.html.
Здесь созданы границы вокруг адаптивных блоков с разных сторон; цвет линии задан
по умолчанию, а толщина- borcter-5. В окне браузера данная страница будет иметь
вид, представленный на рис. 3.21.
Как видно из рис. 3.21, адаптивные блоки имеют ограничительные линии, расположен
ные с разных сторон.
0 Ьorder_l )( + V
f- ➔ С (D Файл I C:/Users/Anatoly/Pycharm... G te * □ е,
-:( Аsиабw,еты О Яндекс "' Перевеа>1 G Gmail
Есть еще один способ обрамления адаптивных блоков, когда можно убирать границу
с одной из сторон. Для этих целей используется следующий класс:
□ class="border-0" -убирается ограничительная линия с четырех сторон;
□ class="border-top-0" -убирается ограничительная линия сверху;
□ class="border-end-0" - убирается ограничительная линия справа;
□ class="border-bottom-0" - убирается ограничительная линия снизу;
□ class="border-start-0" -убирается ограничительная линия слева.
Пример НТМL-кода страницы, в которой показано создание границ вокруг адаптивных
блоков путем удаления ограничительной линии с одной из сторон, приведен в листин
ге 3.11, страница border_2.html.
<!ООСТУРЕ html>
<html lang="en">
<head>
<title>border 2</title>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container text-center bg-primary">
<div class="row bg-success text-white">
<div сlаss="соl">Обозначение границ вокруг адаnтивных блоков</div>
</div>
<div class="row my-2">
<div class="col mx-2 bg-info border Ьоrdеr-О">Блок l</div>
<div class="col mx-2 bg-info border border-5 border-top-O">Блoк 2</div>
<div class="col mx-? bg-info border border-5 border-end-O">Блoк 3</div>
<div class="col mx-2 bg-info border border-5 border-bottom-0">
Блок 4</div>
<div class="col mx-2 bg-info border border-5 border-start-0">
Блок 5</div>
</div>
<div class="row"></div>
</div>
</body>
</html>
Здесь заданы границы вокруг адаптивных блоков с разных сторон. Цвет линии уста
новлен по умолчанию, а толщина - borcter-5. В окне браузера эта страница будет иметь
вид, представленный на рис. 3.22.
Как видно из данного рисунка, ограничительную линию можно удалить либо со всех
сторон адаптивного блока, либо с одной из сторон.
Макетирование НТМL-страниц с фреймворком Bootstrap 89
0 Ьorder_2 х + V
с= Г;"9 �
Обозначение границ вокруг адаптивных блоков
L_J
Рис. 3.22. Различные варианты обозначения границы вокруг адаптивного блока
путем удаления ограничительной линии с одной из сторон
Изменить цвет границы вокруг адаптивного блока можно с помощью следующих клас
сов:
□ class="border border-primary"; □ class "border border-info";
=
Здесь заданы цвета рамок границы вокруг адаптивных блоков с разных сторон толщи
ной линии ьorcter-5. В окне браузера данная страница будет иметь вид, представленный
на рис. 3.23.
0 +
*
border_color х V
Как видно из рис. 3.23, для ограничительных рамок можно задавать разные цвета. Об
ратите внимание на блоки 7 и 1 О, на которых не видно ограничительных рамок. Это
связано с тем, что ограничительные рамки имеют тот же цвет, что и фон.
Углы ограничительных рамок можно округлить, для этого предусмотрены следующие
классы:
□ class="roundect";
□ class="rounded-top";
□ class="rounded-enct";
□ class="rounded-bottom";
□ class="rounded-start";
□ class="rounded-circle";
□ class="rounded-pill".
Пример НТМL-кода страницы, в которой показано создание рамок с округленными
углами, приведен в листинге 3.13, страница border_radius.html.
Макетирование НТМL-страниц с фреймворком Bootstrap 91
<!ООСТУРЕ html>
<html lang="en">
<head>
<title>border_radius</title>
<rneta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<Ьоdу>
<div class="container text-center">
<div class="row bg-success text-white">
<div сlаss="соl">Обозначение границ вокруг адаптивных блоков</div>
</div>
<div class="row my-2">
<div class="col mx-2 bg-warning border border-3
border-primary rounded">Блoк l</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-top">Блoк 2</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-end">Блoк 3</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-bottom">Блoк 4</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-start">Блoк 5</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-circle">Блoк 6</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-pill">Блoк 7</div>
</div>
<div class="row"></div>
</div>
</body>
</html>
Здесь заданы рамки вокруг адаптивных блоков с толщиной линии border-з, при этом
реализованы разные варианты округленных углов. В окне браузера данная страница
будет иметь вид, представленный на рис. 3.24.
0 Ьorder_radius х +
*
V
� ➔ С (D Файл I C:/Users/Anatoly/PycharmProjects/Boot_Start/border_radius.html te □ �
�\ Авиабилеты О Янд•i<С Перевести G Gmail
Рис. 3.24. Различные варианты округленных углов рамок вокруг адаптивного блока
92 Глава 3
Можно задать радиус округления углов ограничительных рамок, для этого используют
ся следующие классы:
□ class="rounded-0";
□ class="rounded-1";
□ class="rounded-2";
□ class="rounded-3";
□ class="rounded-4";
□ class="rounded-5".
Пример НТМL-кода страницы, в которой показано создание рамок с разными радиуса
ми округления углов, приведен в листинге 3.14, страница border_radius_l.html.
<!ООСТУРЕ html>
<html lang="en">
<head>
<title>border_radius_l</title>
<meta charset="UTF-8">
<meta name="viewport" content= "width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container text-center">
<div class="row bg-success text-white">
<div сlаss="соl">Обозначение границ вокруг адаптивных блоков</div>
</div>
<div class="row my-2">
<div class="col mx-2 bg-warning border border-3
border-primary rounded-O">Блoк 1</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-l">Блoк 2</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-2">Блoк 3</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-З">Блoк 4</div>
<div class="col mx-2 bg-warning border border-3
border-primary rounded-4">Блок 5</div> _
<div class="col mx-2 bg-warning border border-3
border-primary rounded-S">Блoк 6</div>
</div>
<div class="row"></div>
</div>
</body>
</html>
Здесь созданы рамки вокруг адаптивных блоков с толщиной линии Ьorcter-3, при этом
заданы разные радиусы округленных углов. В окне браузера данная страница будет
иметь нид, представленный на рис. 3.25.
Макетирование НТМL-страниц с фреймворком Bootstrap 93
+ V
f- ➔ С ф Файл I C:/Users/Anatoly/PycharmProject... � * □ 6
� Авиабилеты О Яндекх: it.i Переоести G Gmail
<!DOCTYPE html>
<html lang="en">
<head>
<title>Start</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container р-3 bg-primary text-white text-center">
<hl>Это страница Bootstrap</hl>
<р>Измените размер этой адаптивной страницы, чтобы увидеть эффект!</р>
</div>
<div class="container mt-3 text-center border border-3">
<div class="row">
<div class="col-sm--4 ">
<hЗ>Колонка 1</hЗ>
<р>Это содержимое</р>
<р>первой колонки</р>
</div>
<div class="col-sm--4 ">
<hЗ>Колонка 2</hЗ>
<р>Это содержимое</р>
<р>второй колонки</р>
</div>
94 Глава 3
На этой странице имеются два контейнера класса container. В первом контейнере нахо
дится текст, во втором - создан один ряд, в котором имеются три адаптивных блока
с вложенным в них текстом. В окне браузера данная страница будет иметь вид, пред
ставленный на рис. 3.26.
0 Start )( + V
Обратите внимание, что при изменении ширины окна браузера. меняется ширина кон
тейнера и их содержимого, при этом окно браузера всегда шире, чем ширина контейне
ров (слева и справа остается свободное пространство). При минимальной ширине окна
браузера колонки трансформируются в три строки, и боковые отступы исчезают, при
этом размер шрифта не уменьшается (рис. 3.27).
В таком виде страница будет отчетливо отображаться как на экране компьютера, так и
на экране смартфона, текст будет оставаться разборчивым и читаемым.
Теперь создадим НТМL-страницу с двумя адаптивными подвижными, или «резиновы
ми» контейнерами на основе класса container-fluid (листинг 3 .16, страница start_ l .html).
Макетирование НТМL-страниц с фреймворком Bootstrap 95
)( + V
Колонка 1
Это содержищ�е
nераой 1СО11онки
Колонка 2
Колонка 3
Это содерх11мо11
Тр@Тl>@Й ICOAOHIG'
<!DOCTYPE html>
<html lang="en">
<head>
<title>Start</title>
<meta charset="utf-8">
<meta name="viewport" content="width= device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<div class="container-fluid р-3 bg-primary text-white text-center">
<hl>Это страница Bootstrap</hl>
<р>Измените размер этой адаптивной страницы, чтобы увидеть эффект!</р>
</div>
+ V
*
)С
f- ➔ С Ф ФаЙI'! 1 C;/Uset'$/A11atoly/l'yФarmPr�e... �В □ (}
Обратите внимание, что при изменении ширины браузера меняется ширина контейнера
и их содержимого, при этом ширина контейнеров всегда соответствует ширине окна
браузера (слева и справа нет свободного пространства). При минимальной ширине
браузера колонки трансформируются в три строки.
На этом мы закончим знакомство с макетированием НТМL-страниц на основе фрейм
ворка Bootstrap. Конечно, в Bootstrap имеется множество различных визуальных эле
ментов для создания привлекательного веб-интерфейса, с которыми вы можете позна
комиться в специальной литературе. Некоторые из этих элементов мы будем применять
в шаблонах НТМL-страниц и более детально познакомимся с ними в следующих главах
на конкретных примерах.
Макетирование НТМL-страниц с фреймворком Bootstrap 97
</tаЫе>
Таблицу создают с помощью следующих тегов:
□ <tаЫе> - создает таблицу;
□ <thead> - заголовок таблицы;
□ <tbody> - тело таблицы;
□ <tr> - строку;
□ <td>- колонку.
В качестве примера создадим НТМL-страницу с таблицей, состоящей из трех строк
и трех колонок (листинг 3.17, страница taЫe.html).
<!DOCTYPE html>
<html lang="en">
<head>
<title>Taблицa</title>
<rneta charset="utf-8">
<rneta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/bootstrap.bundle.min.js"></script>
</head>
<body>
<tаЫе class="taЫe">
<thead>
98 Глава З
<tr>
<th>№</th>
<th>Фамилия</th>
<th>Имя</th>
<th>E-mail</th>
</tr>
</thead>
<tЬody>
<tr>
<td>l</td>
<td>Иванов</td>
<td>Ивaн</td>
· <td>ivan@mail.ru</td>
</tr>
<tr>
<td>2</td>
<td>Пeтpoв</td>
<td>Пeтp</td>
<td>petr@mail.ru</td>
</tr>
<tr>
<td>З</td>
<td>Cидopoв</td>
<td>Ceмeн</td>
<td>sid@mail.ru</td>
</tr>
</tbody>
</tаЫе>
</body>
</html>
0 Таблиц,,
Для того чтобы создать для таблицы границы, используется класс taЫe-Ьordered. Изме
ним в листинге 3.17 следующим образом строку с классом tаые:
<tаЫе class="taЫe taЫe-bordered">
После этого таблица примет вид, представленный на рис. 3.30.
с::, (i) �
)( + V
Если таблица используется для макетирования страницы, то все границы можно уда
лить, для чего предусмотрен класс taЬle-borderless. Для удаления границ изменим
следующим образом строку с классом taЬle в листинге 3.17:
<taЬle class="taЬle taЬle-borderless">
После этого таблица примет вид, представленный на рис. 3.31.
0 Таблица )( +
f- ➔ С Ф Файл I C:/Users/Anatoly/P... � * □ е},
� Аоиа6'41\- О Яндекс 1111 Переоестм G Gmail
Считается хорошим тоном, когда четные и нечетные строки таблицы выделены альтер
нативщ,IМи цветами. В Bootstrap это можно сделать с помощью класса taЬle-striped.
Изменим в листинге 3.17 следующим образом строку с классом taЬle:
<taЬle class="taЬle taЬle-striped">
После этого таблица примет вид, представленный на рис. 3.32.
100 Глава З
)( + у
f- ➔ С Ф Файл I C:/Users/Anatoly/P... !В * [1 е,
-:,(' Ааиабмлеты О Яндекс !115 Переаесr" G Gmoil
<!ОСХ::ТУРЕ html>
<html lang="en">
<head>
<title>Taблицa</title>
<rneta charset="utf-8">
<rneta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="static/css/bootstrap.min.css" >
<script defer src="static/js/Ьootstrap.bundle.min.js"></script>
</head>
<body>
<taЬle class="taЬle">
<thead>
Макетирование НТМL-страниц с фреймворком Bootstrap 101
<tr>
<th>Цвeт</th>
<th>Клacc</th>
</tr>
</thead>
<tЬody>
<tr>
<td>Default</td>
<td>Default</td>
</tr>
<tr class="taЫe-primary">
<td>Primary</td>
<td>class="taЫe-primary"</td>
</tr>
<tr class="taЫe-success">
<td>Success</td>
<td>class="taЫe-success"</td>
</tr>
<tr class="taЫe-danger">
<td>Danger</td>
<td>class="taЫe-danger"</td>
</tr>
<tr class="taЫe-info">
<td>Info</td>
<td>class="taЫe-info"</td>
</tr>
<tr class="taЫe-warning">
<td>Warning</td>
<td>class="taЬle-warning"</td>
</tr>
<tr class="taЫe-active">
<td>Active</td>
<td>class="taЬle-active"</td>
</tr>
<tr class="taЬle-secondary">
<td>Secondary</td>
<td>class="taЬle-secondary</td>
</tr>
<tr class="taЬle-light">
<td>Light</td>
<td>class="taЬle-light"</td>
</tr>
<tr class="taЬle-dark">
<td>Dark</td>
<td>class="taЬle-dark"</td>
</tr>
</tbody>
</tаЫе>
</body>
</htrnl>
В окне браузера данная страница будет иметь вид, представленный на рис. 3.33.
102 Глава 3
х V
* е-
0 Тоблица
Цнт Класс
Default Default
Prlmary
SUa:ess
�
�r class='table-danger"
1 lnfo class="taЫe-info"
'Warning class="taЫe-waming"
Active class="table-active"
Secondary class="table-secondary
Ught class="taЫe-light"
В этой главе мы ответим на вопрос «Что такое Django?» и поясним, почему этот
фреймворк столь привлекателен для программистов. Мы также покажем вам некоторые
основные базовые блоки приложения, написанного с помощью Django (хотя у вас пока
еще не будет среды разработки и тестирования). В общих чертах мы познакомимся со
структурой и основными элементами Django, ·структурой приложений на нем, основ
ными понятиями и определениями. В процессе изучения материала главы:
□ будет создан первый проект на Django;
□ рассмотрены понятия о «представлениях» и «маршрутизации» при разработке веб
приложений на Django.
Итак, приступим к знакомству с основами работы Jia Django.
,"
------
1
Jiа11ВЬ1Х )
_,.. 1 �
+ ----------
�
1 1
+
1 \
'
1 _,..-:..-:..-:.----. шаблояа
Загрузка
- - -- ,1
/ 1
I
1' 1
' -------- ,;#
L
,r;: _;а
Мodel Шаблоны
DB
tE+ (models.py) (filename.htm!)
После выполнения этой команды в папке Web_1 проекта PyCharm будет создана новая
папка hello проекта Django (рис. 4.4).
Все веб-проекты на Django имеют одинаковую структуру. Изучим более детально эту
структуру на примере нашего проекта hello (рис. 4.5), последовательно рассмотрев
каждую папку и файл начального проекта, который пока не содержит приложений:
□ папка Web_1/- корневой каталог (папка) нашего проекта PyCharm. Она представля
ет собой контейнер, в котором будут создаваться наши Djаngо-проекты, приложения
108 Глава 4
Т erminal: Local +
Microsoft Windows [Version 6.1.7601]
(с) Корпорациq Майкрософт 2013. Все права защищены.
и прочие файлы для управления проектом. Название папки ничего не значит для
Django, и его можно поменять на свое усмотрение;
□ папка Web_ 1/ hello - это внешняя папка веб-проекта Django, которая содержит мо
дуль для управления проектом и вложенную папку с аналогичным названием;
□ файл manage.py- это менеджер проекта, или инструмент управления проектом из
командной строки (в частности, при помощи этого менеджера можно запустить про
ект на исполнение на локальном веб-сервере Django);
□ папка Web_ 1/hello/hello/ - внутренняя папка проекта Django. Она содержит текущий
и единственный на данный момент пакет (или, вернее, проект).
ВложеIIИЬJе Пantal.
Файлы
manage.py
, asgi
.
py J
settings_PYJ
ш1s.ру
1
wsgj.py 1
Рис. 4.5. Структура проекта Django с именем hello
функций. Один проект может включать множество приложений. Таким образом, боль
шой проект можно разбить на отдельные приложения и разрабатывать их относительно
независимо друг от друга. Кроме того, это позволит затем переносить некоторые при
ложения из одного проекта в другой, тем самым сокращая сроки разработки проектов.
Пока мы создали только проект Django, в котором еще нет ни одного приложения. Не
смотря на это, мы уже можем выполнить контрольный запуск проекта. Сначала нужно
войти в папку hello, для чего в окне терминала PyCharm выполнить следующую команду:
cd hello
В результате этого будет выполнен переход из корневой папки Web_1 в папку hello про
екта Django (рис. 4.6).
Теперь, находясь в этой папке, можно запустить наш проект на выполнение. Наберите
в окне терминала команду запуска локального веб-сервера:
python manage.py runserver
В результате выполнения этой команды будет запущен локальный веб-сервер разработ
ки на вашем компьютере с адресом Ьttp://127.0.0.1:8000/ (рис. 4.7).
ПРИМЕЧАНИЕ
Если после выполнения этой команды вы получили сообщение об ошибке:
UnicodeDecodeError: 'utf-8' codec can't decode byte Oxcf in position 5:
invalid continuation byte
то это означает, что в имени вашего компьютера присутствуют символы кириллицы - на
пример, Vlt-ПK. В таком случае нужно войти в свойства компьютера и поменять его имя
(убрать символы ПК). Для этого следует щелкнуть правой кнопкой мыши на значке Мой
компьютер, в открывшемся меню активировать опцию Свойства и выбрать левой кнопкой
мыши ссылку Изменить параметры (рис. 4.8).
В открывшемся окне Свойства системы на вкладке Имя компьютера нажмите кнопку Из
менить - откроется панель Изменение имени компьютера или домена, в которой мож
но убрать символы русского алфавита из имени компьютера. В данном случае имя компью
тера Vlt-ПK было заменено на Vlt (рис. 4.9).
. �
.у,,,__.,.
•Нocтpolu•
,IP-,-rpt
,,._._
·д,,c-ynpot"lc,I
------�--.
н..-ri,o11"y_..,.
-·
$ дll<nетч,р устро'1<та
• ДonoJtrtНYvtw.we м�е,рw
Прочк<ор,
у.,,
___ ......,..
(ОЗУ):
кoun•мntpl
1m1(Я) Co,il(Т"I) iS•JS1V CPU О
ЗАОGНz ЗАО GНz
4,00l'i
Цttrтpn-
Цttrтp о6ноал..... Windows
С�мьмс�тu
nроклсwпел•ностм
..:1
Рис. 4.8. Окно входа в режим изменениА параметров компьютера
# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/ilBn/
LANGUAGE CODE = 'en-us'
TIME ZONE = 'UTC'
USE I18N True
USE Ll0N True
USE TZ True
т
дополнительно Защи а системы Удаленный дос:-туn
Имя компыотера Оборудооание
1
Описание:
Можно ИзмеtМlЬ ИМЯ и принадnежнос'ТЬ этого
Например: "Компьютер 6 ГОС1ИНОЙ" ИЛИ компыотер а.. Изменения могуrповлия,ь на дос1УП к
"Компьютер днпрея". сетевым ресурсам. П одообносш
Полное имя: VHlК
ок О1>аена
ок Отмена J Пр1.1r--1енн
� ➔ С (D 127.0.0.1:8000 �* е
::; При11о.же"ия М Gm21il D YouTu� l.f Карты
Как можно видеть, здесь по умолчанию задан английский язык в его американской вер
сии (en-us). Задайте в этой опции русский язык (рис. 4.12):
LANGUAGE CODE = 'ru-ru'
f- ➔ с Ф 121.0.0.1,аооо * е
::: Прм=ния М Gmoil D YouTuЬe r, К•рты
DATAВASES = {
'default':
'ENGINE': 'django.c!Ь.backends.sqliteЗ',
'NАМЕ': os.path.join(BASE_DIR, 'c!Ь.sqlite3'),
Именно здесь можно переопределить базу данных, с которой будет работать приложе
ние. Чтобы работать с другими системами управления базами данных (СУБД), необхо
димо установить соответствующий дополнительный пакет (табл. 4.1).
Таблица 4.1. Основные базы данных, с которыми может работать приложение Django
□ django.contrib.contenttypes;
□ django.contrib.sessions;
□ django.contrib.messages;
□ django.contrib.staticfiles.
Список всех приложений, созданных по умолчанию, можно найти в переменной
INSTALLED-APPS файла проекта settings.py:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
Теперь у нас все готово для работы над своими приложениями, в которых мы сможем
реализовать нужный нам функционал. Создадим в нашем проекте первое приложение,
для которого затем напишем собственный программный код.
Для создания нового приложения в окне терминала PyCharm выполните следующую
команду (рис. 4.15):
python manage.py startapp firstapp
Имя приложения может быть любым - оно указывается после команды startapp.
Т erminal: Local +
Microsoft Windows [Version 6.1.7601)
(с) Корпорация Майкрософт 2013. Все права защищены.
В окне среды разработки PyCharm это будет выглядеть следующим образом (рис. 4.17).
В проекте может быть несколько приложений, и каждое из них нужно будет добавлять
аналогичным образом. После добавления приложения firstapp полная структура нашего
веб-приложения будет выглядеть так, как показано на рис. 4.18.
Теперь определим какие-нибудь простейшие действия, которые будет выполнять это
приложение, - например, на запрос пользователя отправит ему в ответ приветствие
Hello World. Напомним, что в запросе пользователь указывает адрес интересующей его
НТМL-страницы, а в ответ получает запрошенную страницу с неким содержимым,
которое формируется сервером. В Django такое упрощенное взаимодействие можно
118 Глава 4
Рис. 4.17. Окно терминала PyCharm: регистрация приложения firstapp в файле settings.py
ВложеВВЬiе папки
Файлы
j
_init_.py
1 _init_ .p;l
]
admin.py
1
settings.py apps.py
]
urls.py models.py
]
wsgi.py
tests.py
1
db.sqliteЗ ]
1
L vie\\'S.py
"i
manage.py
Рнс. 4.18. Полная структура файлов и папок веб-приложения с проектом hello и приложением firstapp
Знакомимся с фреймворком Django 119
Это самое простое представление, которое можно реализовать в Django. Чтобы вызвать
данное представление, нам нужно сопоставить его с URL-aдpecoм, а для этого нам
нужна конфигурация URL. Для того чтобы создать URLconf, в каталоге firstapp создайте
новьiй файл с именем urls.py. Каталог вашего приложения теперь должен выглядеть сле
дующим образом:
firstapp
migrations
_init_.py
admin.py
apps.py
models.py
tests.py
urls.py
vievs.py
Чтобы использовать функцию views.index, в листинге 4.2 вначале выполнен импорт мо
дуля views. Затем маршрут ('') - это, по сути, запрос пользователя к корневой страни
це сайта, сопоставлен с функцией views.index, а также дополнительно задано имя для
этого маршрута (name=' index'). В результате, если пользователь запросит показать глав
ную(корневую) страницу сайта(''), то будет вызвана функция index из файла views.py.
120 Глава 4
Следующий шаг - указание корневого URLconf. Для этого открьmаем файл hello/urls.py,
и пишем в нем код, приведенный в листинге 4.3.
0 127.0.0.1:8000 х + V
f- ➔ С (D 127.0.0.1:8000
(
1 Авиабилеты О Яндекс � Пер�вест.t G Gmail
Несколько слов о функции path(), которую мы использовали в листинге 4.3. Эта функ
ция принимает четыре аргумента: два обязательных route и view и два необязательных
kwargs и name. Пришло время рассмотреть, зачем нужны эти аргументы.
Знакомимся с фреймворком Django 121
□ Арrумент route (маршрут, путь)- это строка, содержащая шаблон URL. Когда
Django обрабатьmает запрос пользователя, он начинает перебор адресов с первого
шаблона urlpattems и продолжает спускаться вниз по списку, сравнивая запрошен
ный URL-aдpec с каждым шаблоном, пока не найдет тот, который соответствует по
лученному от пользователя.
Обратите внимание, что эти регулярные выражения не ищут параметры GET и POST
или имя домена. Например, в запросе к URL-aдpecy https://www. ехащ:йе.corn/myapp/
URLconf будет искать только myapp/.
В запросе к адресу https://www .example.com/myapp/?page=З URLconf также будет искать
ТОЛЬКО myapp/.
□ Арrумент view. Когда Django находит совпадение с регулярным выражением, он
вызывает функцию, указанную в view с объектом HttpRequest в качестве первого
аргумента и любыми «пойманными» значениями пути в качестве аргументов клю-
чевого слова. Детально использование этого аргумента будет рассмотрено чуть поз
же на конкретных примерах.
□ Арrумент kwarqs. Описание данного аргумента мы пропустим, поскольку в приме
рах данной книги эта функциональность Django нам не понадобится.
□ Арrумент name. Имя URL-aдpeca позволяет однозначно ссьmаться на данный адрес
из других частей Django, особенно из шаблонов. Это достаточно мощная и полезная
функциональность, которая позволяет вносить глобальные изменения в шаблоны
URL-aдpecoв проекта, изменяя только один файл.
Поскольку маршрутизация запросов пользователя является ключевым моментом при
разработке веб-приложений на Django, мы изучим маршрутизацию более подробно
в следующей главе.
Представления и маршрутизация
В этом коде мы, по сути, запрограммировали функции для выдачи заголовков · трех
страниц сайта: Главная (index), О сайте (about), Контакты (contact), как показано на
рис. 5.1.
Г.паввu
Оам1ц)
Осайrе
(aЬout)
Ковтапы
(c:oatact)
В нашем случае здесь определены три функции, которые будут обрабатывать запросы
пользователя. Каждая функция принимает в качестве параметра объект request (запрос).
Для генерации ответа в конструкторе объекта нttpResponse (ответ НТТР) имеется неко
торая строка. В данном случае ответом является строка кода НТМL.
Чтобы эти функции сопоставлялись с запросами пользователя, нужно в файле
firstapp/ur1s.py проекта firstapp определить для них маршруты. В частности, изменим этот
файл, как показано в листинге 5.2.
Представления и маршрутизация 125
� ➔ С (D 127.0.0.1:8000
••• Приложения М Gmail D YouTube Р1 Карты
Главная
Рис. 5.2. Главная страница сайта
� ➔ С Ф 127.0.0.1:8000/about
Ш При.пожения М Gmail D YouTube
О сайте
Рис. 5.3. Страница сайта О сайте
� ➔ С (D 127.0:0.1:8000/contact
... Приложения М Gmail D YouTube 1! Карты
Контакты
Рис. 5.4. Страница сайта Контакть1
126 Глава 5
.
пользователь Request Response (НТМL)
1 '
+
,J
Прнложевне Django
URLS (urls.py)
R« •. views.index)
1
---i R«aЬouf, views.aЬout)
1
�
!Шh('contact', views.contact)
1
View (views.py)
-. � contact(request):
Ш\1m HttpR.esponse("<h2>Koвтaпы<.1Ы>")
L...-,i, � aЬout(request):
Ш\1m HttpR.esponse("<h2>0 с.айте</h2>")
-. � index{request):
ШtJm HttpR.esponse("<h2>Глaвнaя</h2>")
urlpatterns =
path ('', views.index),
re_path(r'лaЬout', views.aЬout),
re_path(r'лcontact', views:contact),
� ➔ С Ф 127.0.0.1:8000/about/
Using the URLconf deflned in hello. urls, Django tried these URL pattems, in this order:
1.
2. about
З. contact
The current path, aЬout/, didn't match алу of these.
Рис. 5.6. Возврат ошибки при обращении к странице aЬout по адресу http:/1127.0.0.1 :8000/about/
� ➔ С Ф 127.0.0.1:8000/about/
О сайте
Рис. 5.7. Корректное обращение к странице aЬout по адресу http:/1127.0.0.1:8000/about/
при использовании функции re_path()
Представления и маршрутизация 129
Адрес Запрос
r'л$' http:l/127.0.0.1/ (корень сайта)
r' лаьоut' http:l/127.0.0.1/about/ или
http:l/127.0.0.1/about/contact
r'лaЬout\contact' http:l/127.0.0.1/about/contact
130 Глава 5
Адрес Запрос
r'лproducts/\d+/' http:l/127.0.0.1/products/23/ или
http:/1127.0.0.1/products/6459/abc
Но не соответствует запросу:
http:/1127.0.0.1/products/abc/
r'лproducts/\D+/' http:/1127.0.0.1/products/abc/ или
http:/1127.0.0.1/products/abc/123
Не соответствует запросам:
,
http:/1127.0.0.1/products/123/ или
http:/1127.0.0.1/products/123/abc
r'лproducts/phonesltaЫets/' http:/1127.0.0.1/products/phones/1 или
http:/1127.0.0.1/products/taЬlets/
Не соответствует запросу:
http:/1127.0.0.1/products/clothes/
r'лproducts/\w+' http:/1127.0.0.1/abc/ или
http:/1127.0.0.1/123/
Не соответствует запросу:
http:/1127.0.0.1/abc-123
r'лproducts/[-\w]+/' http:/1127.0.0.1/abc-123
r'лproducts/[A-Z]{2)/' http:/1127.0.0.1/RU
Не соответствует запросам:
http:/1127.0.0.1/Ru или
http:/1127.0.0.1/RUS
Здесь функция products кроме параметра request принимает также параметр productid
(идентификатор товара). Отправляемый пользователю ответ содержит значение этого
параметра.
Функция users принимает два дополнительных параметра: id и name (идентификатор и
имя пользователя). И подобным же образом эти данные отправляются обратно пользо
вателю.
Теперь изменим файл urls.py, чтобы он мог сопоставить эти функции с запросами поль
зователя (листинг 5.7, изменения выделены серым фоном).
urlpatterns = [
re_path(r'лcontact/', views.contact),
re_path(r'лapout', views.aЬout),
pr id>\d+)/', views.products),
\d �e>\D+j7• i. vi�s.user§.1,
path('', views.index) ,
(- ➔ С ф 127.0.0.1:8000
Главная
Рис. 5.8. Главная страница сайта, загруженная по умолчанию
� ➔ С Ф 127.0.0.1:8000/products/5/
ш """'-""' м ·� ..,,. - -
ПродуктNо 5
Рис. 5.9. Страница сайта, возвращенная пользователю, запросившему информацию о продукте № 5
f- ➔ с
Ш Приложения
Однако если мы в запросе не укажем значение для параметра или передадим значение,
которое не соответствует регулярному выражению, то система не сможет найти ресурс
для обработки такого запроса и выдаст сообщение об ошибке. Например, если пользо-
Представления и маршрутизация 133
� ➔ С (D 127.0.0.1:8000/products/
Using lhe URlconf defined in hello.urls, Django tried these URL pattems, in this order:
1.
2. AaЬout
3. "contact
4. лproducts/(?P<productid>\d+)/
5. "users/ (?P<id>\d+)/(?P<name>\D+)/
Тhе current path, products/, didn't match any of these.
Теперь, если в функцию не бьшо передано значение для параметра productid, то он по
лучает значение по умолчанию 1.
В этом случае в файле urls.py нужно дополнительно определить еще один маршрут:
re_path(r'лproducts/$', views.products),
Добавив эту строчку, мы в итоге получим следующее содержание файла urls.py (лис
тинг 5.9, изменения вьщелены серым фоном).
re_path(r'лproducts/(?P<productid>\d+)/', views.products),
_path r•л roductsl$ 1 views.m:oducts), # �шру,г по умщrчанию
re_path(r'лusers/(?P<id>\d+)/(?P<narne>\D+)/', views.users),
path(' ', views. index),
Теперь если в запросе пользователя не будет указан id продукта, то система вернет ему
не страницу с ошибкой, а страницу с номером продукта, который в функции products
был задан по умолчанию: productid;l (рис. 5.12).
Ш Приложения Карты
Продукт№ 1
Рис. 5.12. Страница сайта, возвращенная пользователю,
запросившему информацию о продукте без указания его идентификатора
def index(request):
return HttpResponse("<h2>Глaвнaя</h2>")
def about(request):
return HttpResponse("<h2>O сайте</h2>")
def contact(request):
return HttpResponse("<h2>Koнтaкты</h2>")
de� products(request, productid;l):
output ; "<h2>Продукт № {0)</h2>".format(productid)
return HttpResponse(output)
def users(request, id, narne):
\output ; "<h2>Пользователь</h2><h3>id:" \
\ "(0) Имя:{1)</hЗ>".. format(id, narne)
return HttpResponse(output)
f- ➔ С ф 127.0.0.1:8000/productsLб/
Как можно видеть, функция path() работает здесь аналогично функции re_path. В зави
симости от предпочтений программиста можно использовать любую из этих функций.
Параметры функции path() заключаются в угловые скобки в формате: /
<спецификатор:название_параметра>
В нашем примере в маршруте обращения к странице с продуктами параметр productid
имеет спецификатор int (целое число).
По умолчанию Django предоставляет следующие спецификаторы параметров функции:
□ str - соответствует любой строке за исключением символа (/). Если спецификатор
не указан, то str используется по умолчанию;
□ int - соответствует любому положительному целому числу;
□ slug - соответствует последовательности буквенных символов ASCII, цифр, дефиса
и символа подчеркивания, например: building-your-lst-django-site;
□ uuid - соответствует идентификатору UUШ, например: 075194d3-6885-417e-a8a8-
6c931e272fOO;
136 Глава 5
□ path - соответствует любой строке, которая также может включать символ (/),
в отличие от спецификатора str.
output = "<h2>Пользователь</h2><h3>id:" \
" {О} Имя:{l}</hЗ>".format(id, name)
return HttpResponse(output)
После этого для функций products и users в файле firstapp/urts.py с использованием функ
ции path() нужно определить по два маршрута: для запроса с заданными параметрами
и для запроса с параметрами по умолчанию (листинг 5.13).
После этих изменений файл firstapp/urls.py будет выглядеть как в листинге 5.14.
urlpatterns = [
re_path(r'лcontact/', views.contact),
re_path(r'лaЬout', views.aЬout),
path('products/', views.products), # маршрут no умолчанию
path('products/<int:productid>/', views.products),
path('users/', views.users), # маршрут по умолчанию
path('users/<int:id>/<str:name>/', views.users),
path('', views.index),
Ш Приложения
ПродуктNо 1
Пользователь
id: 1 Имя: Максим
Рис. 5.14. Страницы сайта, возвращенные пользователю,
запросившему информацию о продукте (вверху) и пользователе (внизу),
с параметрами по умолчанию при использовании функции path() в файле ur1s.py
Как можно видеть, при отсутствии параметров в запросе пользователя функция path()
не выдает здесь ошибку, а возвращает ответные страницы с параметрами функций по
умолчанию.
А вот в запросе:
http://localhost/index?id=3&name= Виктор
те же самые значения 3 и Виктор представляют собой параметры строки запроса.
Параметры строки запроса указываются после символа вопросительного знака (?).
Каждый такой параметр представляет собой пару «ключ-значение». Например, в пара
метре id=З: id- это ключ параметра, а 3- его значение. Параметры в строке запроса
отделяются друг от друга знаком амперсанда (& ).
Для получения параметров из строки запроса применяется метод request. GET. get().
Например, переопределим в файле firstapp/views.py функции products() и users(), как пока
зано в листинге 5.15 (изменения выделены серым фоном).
0 127.0.0.l:SOOO{products/ х + 0 127.0.0.1:8000/products/3/ х +
� ➔ С Ф /products
127.0.0.1: 8000 /
( По умолчанию
!:i! .. . .
k�
�.
0 127.0.0.1:8000/products/3/?catc Х +
Рис. 5.15. Страница сайта, возвращенная пользователю, при разных параметрах запроса
Как видно из данного рисунка, при обращении к странице products без указания пара
метров вернулся ответ с параметрами по умолчанию. При указании в запросе числа 3
оно будет представлять фрагмент URL, присваиваемый параметру productid, а значение
саt=Телефоны - представлять параметр cat в строке запроса.
Теперь вьшолним обращение к странице users по следующим адресам:
□ http://127.0.0.1:8i)00/users/;
□ http://l27.0.0.1:8000/users/?id=8&name=Aлeкceй.
Вьшолнив эти действия, получим следующие результаты (рис. 5.16).
0 127.0.0.1:8000/users/ х + 0 127.0.0.1:8000/users/?id=4&na• Х +
:Ь-.--/
� ➔ С Ф 127.0.0.1:8000/users/ � ➔ С ф 127.0.0.1:
/users
8000Лid=4&name=A11eкceй
( Поумолчанию
Пользователь/ Пользователь
id: Не задано Имя: Не задано id: 4 Имя: Але1,.-сей
Как видно из данного рисунка, при обращении к странице users без указания парамет
ров, вернулся ответ с параметрами по умолчанию. Во втором случае значения иденти
фикатора - 4 и имя - Алексей преданы на страницу сайта через параметры id и narne.
Итак, мьi рассмотрели очень важные моменты, связанные с адресацией запросов поль
зователя и формирования для него ответных страниц. Но часто возникает потребность
в переадресации, поскольку после модификации сайта данные могут быть перемещены
по другому адресу. Перейдем теперь к рассмотрению способов решения вопроса пере
адресации.
def index(request):
return HttpResponse("<h2>Главная</h2>")
def aЬout(request):
return HttpResponse("<h2>0 сайте</h2>")
def contact(request):
>"
def products(request, productid=l):
category = request.GET.get("cat", "Не задана")
output = "<h2>Продукт № {О} категория: {1}</h2>"\
.fonnat(productid, category}
return HttpResponse(output)
Представления и маршрутизация 141
def users(request):
id = request.GEТ.get("id", "Не задано")
name = request.GEТ.get("name", "Не задано")
output = "<h2>Пользователь</h2> <hЗ>id: (0) Имя: {1}</hЗ >"\
.format(id, name)
return HttpResponse(output)
de
Что мы здесь сделали? При обращении к функции contact она станет перенаправлять
пользователя по пути "aЬout", который будет обрабатываться функцией aЬout. А функ
ция ctetails реализует постоянную переадресацию и перенаправит пользователя на «ко
рены> (главную страницу) веб-приложения.
Для этого примера нам также необходимо в файле firstapp/ur1s.py добавить новый мар
шрут - ctetails (листинг 5.17, изменения выделены серым фоном).
path('', views.index),
Для проверки работы переадресации в окне терминала запустим локальный сервер раз
работки:
python manage.py runserver
� ➔ С ф 127.0.0.1:8000
Ш Припожен-ия М Gmail D YouTube Карты
Index
f- ➔ С ф 127.0.0.1:8000/about/
About
Рис. 5.18. Переадресация на страницу About при попытке вызова страницы contact
f- ➔ С ф 127.0.0.1:8000
In.dex
Рис. 5.19. Переадресация на страницу lndex при попытке вызова страницы details
def m403(request):
return HttpResponseForЬidden("<h2>ForЬidden</h2>")
def m404(request):
return HttpResponseNotFound("<h2>Not Found</h2>")
def m405(request):
return HttpResponseNotAllowed("<h2>Method is not allowed</h2>")
def m410(request):
return HttpResponseGone("<h2>Content is no longer here</h2>")
def m500(request):
return HttpResponseServerError("<h2>Something is wrong</h2>")
Реализуем небольшой пример отправки пользователю статусных кодов. Откроем файл
views.py и добавим в него новую функцию с именем access (листинг 5.18).
Для проверки отправки статусных кодов в окне терминала запустим локальный сервер
разработки:
python manage.py runserver
Теперь в адресной строке браузера наберем адрес страницы access и передадим в ад
ресной строке запроса три разных возраста:
□ /access/Г20;
□ /access/25;
□ /access/12.
В результате этих действий с сервера будут получены следующие ответы (рис. 5.20).
Как видно из данного рисунка, при разных значениях возраста, переданного в запросе
пользователя, сервер вернул разные статусные ответы.
с:, @] 1Z
f- ➔ С ф 127.0.0.1:8000/access/120 � *e_ □ �
�
--- --- -- ---- �� -11сщ>аст120
- -о-
Не1<оррекrньrе дU111Ь1е о�
+
ф 127.0.0.1:8000/access/25 е. � * □
�
Доступразрешев �
)( +·
� ➔ с ф 121.м,_,"""'"Е � 6
:1
' Доступ ,абпоароваи: ведос:rа:rочво .,п �
Шаблоны в Django
heUo
fustapp
heUo
_init_.py
-init_.py '1 L- _init_.py
asgi.py admin.py
1
]
settings.ру apps.py
шls.py models.py
)
]
-w-sgi.py tests.py
db.sqtite3
Yie\VS.py
1
manage.py
TEMPLATES =
{
'BACKEND': 'django.template.backends.django.DjangoTemplates',
'DIRS': [],
'APP_DIRS': True,
'OPTIONS': {
'context_processors': [
'django.template.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
rt о
ТD«РIАТЕ DIR = os.�tli.join(ВASE DIR
TEМPLATES = [
{
'BACKEND': 'django.ternplate.backends.django.DjangoTemplates',
'DIRS': [Т!МPIAТE_DIR,],
'APP_DIRS': True,
'OPTIONS' : {
'context_processors':
'django.ternplate.context_processors.debug',
'django.template.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
},
},
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8 ">
<title>Title</title>
</head>
<body>
</body>
</html>
148 Глава б
После этих изменений наш первый шаблон в окне IDE PyCharm будет выглядеть так,
как представлено на рис. 6.6.
По сути, это обычная страница или файл, содержащий код НТМL. Теперь используем
эту страницу для отправки ответа пользователю. Для этого перейдем в приложении
firstapp к файлу firstapp/views.py, который определяет функции для обработки запроса
пользователя, и изменим этот файл так, как показано в листинге 6.4.
150 Глава б
Чтобы это проверить, откроем файл firstapp/urls.py (рис. 6.8) и убедимся, что в нем для
обрашения пользователя к «корню» веб-приложения прописан следующий маршрут:
path(", views.index)
Шаблоны в Django 151
0 Привет Django! )( +
� ➔ С (D 127.0.0.1:8000
Ш Прw,ожения М Gmail а YouTube 8 Карты
Пока наш шаблон пустой, т. е. это обычная статичная НТМL-страница, но это не беда.
Теперь мы можем вносить в этот шаблон изменения, менять его структуру и дизайн,
вставлять в него данные, полученные из БД, и возвращать пользов�цеmо не статичные,
а динамически генерируемые веб-страницы.
Шаблоны Django представляют собой традиционные НТМL-файлы, которые дополне
ны специальными тегами и программным кодом, позволяющим использовать перемен
ные, циклы и другие управляющие структуры. Когда представление вызывает функцию
rencter () , она передает данные в шаблон, а шаблон генерирует НТМL-код для отображе
ния пользоватеmо. В НТМL-страницах, которые являются шаблонами, применяется
встроенный язык, который называется языком шаблонов Django или DTL (Django
Template Language). С языком шаблонов DTL мы детально познакомимся чуть позже
в следующих разделах, а пока разберемся с тем, где и как можно размещать шаблоны.
ВложенВЪiе пап:кк
,____.i Файлы
_init_.i::=J _init_.py
asgi.py 7J
�---J admin.py
settmgs.py] apps.py
L
urls.py models.py
tests.py
<!DOCTYPE html>
<html lang="en">
<head>
<rneta charset="UTF-8 ">
<titlе>Привет Django</title>
</head>
<body>
<hl>Домашняя страница Django!</hl>
<h2>teпplates/firstapp/home.html</h2>
</body>
</html>
Теперь изменим файл firstapp/views.py нашего приложения, указав в нем новый путь
к странице, которую нужно выдать пользователю при его обрашении к домашней стра
нице сайта - home.html (рис. 6.12).
def index(request):
return render(request, "firstapp\home.html")
0 Привет Django х +
� ➔ С ф 127.0.0.1:8000
ратором разветвления if или циклом for, вьшодить содержимое из базы данных или
даже разрешать доступ к другим тегам шаблона.
Теги имеют следующие обрамляющие символы: { % tag % J. Для некоторых тегов требу
ются начальные и конечные теги, например:
{% tag %)
... tag contents ...
{% endtag %)
Django поставляется с двумя десятками встроенных тегов, о которых можно узнать из
документации по Django 4.1.4 по следующей ссылке:
https://django.readthedocs.io/en/stable/ref/templates/Ьuiltins.html#ref-templates
builtins-tags
Как использовать наиболее употребительные теги, мы далее более детально покажем на
конкретных примерах.
Фильтры. Фильтры позволяют выполнить преобразование значения переменных и
аргументов тегов. Синтаксис фильтров - { { variaЫe I filter )).
Например, в шаблоне возможен следующий фильтр:
{{ valueltitle ))
ПРИМЕЧАНИЕ
Термин «фильтр» в Django немного отличается от общепринятого понятия «фильтр». На
самом деле фильтры не выполняют фильтрацию данных по какому-либо признаку, они
преобразуют значение переменной value от одного вида к другому.
Здесь value - это переменная, а title - это встроенный фильтр, который преобразует
первые символы каждого слова строки в заглавный регистр.
Например, в параметре context функции render через переменную value предается
в шаблон с использованием словаря следующее значение:
{'value': 'это nример использования фильтров в шаблонах.')
Если в шаблоне задан фильтр { { valueltitle )), то пользователь на странице НТМL,
которая вернется с сервера, получит следующий ответ:
Это Пример Использования Фильтров В Шаблонах.
Django поставляется с двумя десятками встроенных фильтров, о которых можно узнать
из документации по Django 4.1.4 по следующей ссьmке:
https://django.readthedocs.io/en/stable/ref/templates/Ьuiltins.html#ref-templates-
builtins-filters
Как применять наиболее употребительные фильтры, мы далее более детально покажем
на конкретных примерах.
Комментарии. В тело шаблона можно вставить комментарии, которые позволяют сде
лать код более понятным. Для создания комментария принят следующий синтаксис:
{# строка с комментарием#)
Комментарий можно размещать в любом месте тела шаблона.
Разберем синтаксис языка DTL на примерах и начнем с переменных.
158 Глава б
l'llilml I r
_init_.pyl _init_.py
admin.py
manage.py
Напишем на этой странице программный код, приведенный в листинге 6.9, при этом
в окне IDE PyCharm наш новый шаблон будет выглядеть так, как показано на рис. 6.15.
<!DOCTYPE html>
<htrnl lang="en">
<head>
<meta charset="UTF-8">
<titlе>Привет Django!</title>
</head>
<body>
<hl>{{header}}</hl>
<р>{{message}}</р>
</body>
</htrnl>
Как можно видеть из листинга 6.9, в теге <body> НТМL-страницы имеются две перемен
ные, написанные на языке DTL: { {header}} и { {message}}. Эти переменные и будут полу
чать значения из представления (view).
file _Eart j(iew !!/av,gate ьоdе ]!elactor Rцn 1ools VQ:i W,ndo,v !::!elp
11WeЬ_l) 11hello)11firstapp) i.l,vi,ws.py
� � Pro;ect • ЕЭ � 1 О - 8'v1ews. бJ. indeк_appl.html Х & 1nde<.html х.
Й: '1' 11WeЬ_l C:\Use�\Vit\Pych.rmPro, 4
�• "11111,110 s
'1' 11firstapp · # python manage. ру гunserveг
► 11migrations
i.l,_ init_.py 8 r0·def index(request):
�admin.py 9 ] # геtuгп гепdег( request, "f...i,,r,.'u.g.p.J2/home. html")
iiapps.py
.. models.py
10
11
т �-
r1i data {"headeг•·: "Передач<1 параметр,ов в шаблон Djc.ingo", "mt.'s.�age":
,.
�-:,-::;- "Загружен шаблон templates/�2RR_/ index_appl. ht,nl"}
fl. tesis.py ____ -r-r- i�:�;? return render( гequest "ti�ЧR.R/ index_appl. html",
# =data)
___i.l, v,ews.py -::---
- 13___��- ----------�--
Рис. 6.16. Изменение кода страницы сайта в файле view.py (согласно листингу 6.1 О)
0 Привет Django! х +
� ➔ С (D 127.0.0.1:8000
••• Приложения М Gmail а YouTube ..: Карты
Рис. 6.17. Домашняя страница сайта с данными, подгруженными в шаблон index_app1 .html
def index(request):
header = "Персональные данные" # символьная переменная
langs = ["Английский", "Немецкий", "Испанский"] # список
user = {"name": "Максим, ", "age": 30} # словарь
addr = ("Виноградная", 23, 45) # кортеж
data = {"header": header, "langs": laпgs, "user": user, "address": addr}
return reпder(request, "iпdex .html", context=data)
Рис. 6.18. Изменение кода страницы сайта в файле view.py (согласно листингу 6.11)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
162 Глава 6
Персова.11ьные данные
Имя: Максим, Age: 30
Результаты работы этого программного кода будут такими же, как на рис. 6.19.
{% endfor %}
<!DOCTYPE html>
<html lang="en">
164 Глава 6
<head>
<meta charset="UTF-8">
<title>Шaблoны</title>
</head>
<body>
<hl>{{header}}</hl>
{% for lang in list_langs %}
<li>{{ lang }}</li>
{% endfor %}
</body>
</html>
Здесь в теле <body> НТМL-страницы сформирован шаблон, который имеет два блока.
Первый блок содержит переменную { {header} J. Во втором блоке организован цикл:
{% for lang in list_langs %)
<li>{{ lang }}</li>
{% endfor %}
В первой строке был создан заголовок цикла. В этом заголовке переменная lang будет
в цикле получать значения иностранных языков, которые содержатся в списке
list_langs. Вторая строка представляет собой тело цикла. Здесь в теге НТМL
<li> ...</li> (список) содержится шаблон Django с переменной { { lang J }, которая бу
дет последовательно выводить те иностранные языки, которые содержатся в списке
list_langs. Наконец в третьей строке обозначено завершение тела цикла. Как выглядит
программный код этого шаблона в окне PyCharm, показано на рис. 6.21.
Теперь в данный шаблон нужно передать список иностранных языков. Для этого от
кроем файл представления firstapp/views.py и напишем в нем код из листинга 6.15.
file _Edit ;tiew �avigate �ode Befactor Rцn Iools VC� Window !:!elp
..
�, "Web_ l с. lci:�1·: д1,аtс1, · р. ,:i,,
Т 18hello <html lang;"en">
► 18firstapp <head>
► 18hello <meta cl1arset="UТF-8">
' Т 18templates <title>Шaблoны</title>
Т 18firstapp </head>
iflihome.htmt <body>
1€1. index_appl.html - --��
- <h1>{{header}}</h1>
ifJ. index.html {% for lang' in list_langs чl1
il? db.sqliteЗ <li>{{ lang }}</li> i
il, manage.py { % t:лo,fgc %} •
► 18venv l1braг, ·cct </Ьоdу>
► 11111 Externaf Libraries </html>
Рис. 6.21. Страница с шаблоном организации цикла в окне IDE PyCharm
Шаблоны в Django 165
Итак, у нас все готово для того, чтобы проверить работу тега организации цикла в шаб
лонах Django. Запустим локальный сервер разработки командой
python manage.py runserver
и перейдем в браузере по адресу bttp://127.0.0.1:8000/. В результате выполненных нами
действий мы увидим в браузере следующую страницу (рис. 6.23).
Как видно из данного рисунка, добавив теr:: для организации цикла в шаблон НТМL
страницы, мы смогли вьmести список иностранных языков.
Тег для организации разветвлений. Синтаксис тега для организации разветвлений
в шаблоне имеет вид:
(% if <логическое_выражение> %}
{ { переменнаяl } }
( % elif <логическое_выражение> %}
{ { переменная2 } }
166 Глава 6
{% else %)
{ { переменнаяЗ ) )
{% endif %)
0 Шаблоны х + V
(- ➔ С ф 127.0.0.1:8000
Иностранные языки
• АнглиiiсЮ!Й
• Немецю�й
• Испансхий
• Французсю!Й
• Итальянсюni
Рис. 6.23. Вывод списка иностранных языков с использованием циклов в шаблонах Django
В первой строке был создан заголовок инструкции if, в котором находится логическое
выражение nurn == 1. Если nurn будет равно 1, то пользователю вернется значение пере
менной varl, а если nurn будет иметь любое другое значение, то пользователю вернется
значение переменной var2. В последней строке обозначено завершение тела блока if.
Как выглядит программный код этого шаблона в окне PyCharm, показано на рис. 6.24.
Теперь в этот шаблон нужно передать значения переменных h�ader, num, varl и var2. Для
этого откроем файл представления firstapp/views.py и напишем в нем код из листинга 6.17.
def index(request):
header = "Разветвления в шаблонах"
nurn = 1
varl "Это nервая ветка в инструкции if"
var2 = "Это вт_орая ветка в инструкции if"
data = { "header": header, "nurn": nurn, "varl": varl, "var2": var2)
return TemplateResponse(request, "firstapp/index_appl.html", data)
Здесь созданы три текстовые переменные header, varl, var2 и числовая переменная nшn.
Эти значения встроены в словарь data, который через функцию request предан в наш
шаблон firstapp/index_app1 .html. Как выглядит программный код файла firstapp/views.py в окне
PyCharrn, показано на рис. 6.25.
Итак, у нас все готово для того, чтобы проверить работу тега организации разветвления
в шаблонах Django. Запустим локальный сервер разработки командой
python manage.py runserver
168 Глава 6
0 х
1=1@1 zg 1
Шаблоны + V
._..- ➔ С ф 127.0.0.1:8000
Разветвления в шаблонах
Это первая ветка в ннсrрvкции if ".=ЕС_�::::::-:-.---------
Рис. 6.26. Станица из шаблона Django с разветвлением при nШIFl
Как видно из данного рисунка, при num=l шаблон вернул пользователю значение пере
менной varl, т. е. сработала первая ветка разветвления в инструкции if. Если теперь
в файле firstapp/views.py изменить значение переменной num, например nШIF2, то шаблон
вернет пользователю значение переменной var2, т. е. сработает вторая ветка разветвле
ния в инструкции if, и пользователю вернется страница, представленная на рис. 6.27.
/с::,/@]/ Ь$ 1
0 Шабюны х + V
,1 ➔ С CD 121.0.0.1:8000
�� Авиабилеты О Яндекс � Перевести G Gmail
Разветвления в шаблонах
Это вторая ветка в инструкции if
Тег для создания фильтров. В шаблонах Django можно использовать фильтры. Обыч
но фильтры позволяют выделить некоторые элементы из группы, но в шаблонах Django
фильтры выполняют иную функцию - они позволяют преобразовать значения пере
менных и аргументов тегов, т. е. можно, например, изменить регистр символов, задать
формат даты, увеличить значение переменной и т. п.
Синтаксис тега для создания фильтров в шаблоне имеет вид:
{{ variaЫe_name filter name }}
Здесь:
□ variaЫe_name - имя переменной, которую нужно преобразовать;
□ filter_name - имя фильтра.
Из фильтров можно создать «цепочку», при этом выходные данные одного фильтра
являются входными данными для. следующего, например { { textltitlellength }}.
В Django достаточно много встроенных фильтров, но мы для примера рассмотрим
только некоторые из них:
□ add - добавляет аргумент к значению;
□ date - преобразуетдату в соответствии с заданным форматом;
□ time - преобразует время в соответствии с заданным форматом;
□ title - преобразует строку в регистр заголовков, заставляя слова начинаться с сим
вола верхнего регистра, а остальные символы - со строчных букв;
□ upper - преобразует
,
все символы строки в верхний регистр.
В качестве шаблона возьмем тот же файл templates/firstapp/index_app1 .html и напишем в нем
программный код из листинга 6.18.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Шaблoны</title>
</head>
<body>
<hl>{{header}}</hl>
<li>{{value_numladd:"2"}}</li>
<li>{{value_dateldate:"D d М Y"}}</li>
<li>{{value_timeltime:"H:i"}}</li>
<li>{{value_titleltitle}}</li>
<li>{{value_upperJupper)}</li>
</body>
</html>
Здесь в теле <body> НТМL-страницы сформирован шаблон из шести строк. Первая стро
ка содержит переменную { {header}}. В остальных пяти строках находятся различные
фильтры. Первая строка заключена в тег НТМL <hl></hq> - заголовок, остальные стро-
170 Глава 6
ки обрамлены тегами НТМL <li></ li> - список. Как выглядит программный код этого
шаблона в окне PyCharm, показано на рис. 6.28.
Теперь в этот шаблон нужно передать значения переменных header, value_nшn, value_date,
value_time, value_title, value_upper. Для этого откроем файл представления firstapp/views.py
и напишем в нем код из листинга 6.19.
def index(request):
header = "Фильтры в шаблонах"
value num = 2
value_date = datetime.datetime.now()
value_time = datetime.datetime.now()
value_title = "это пример использования фильтров"
value_upper = "это строка в верхнем регистре"
data = {"header": header, "value_num": value_num, "value date": value_date,
"value_time": value_time, "value_title": value_title,
"value_upper": value_upper)
return TerrplateResponse(request, "firstapp/index_appl.html", data)
Здесь был импортирован модуль Python datetime, который позволяет получить текущую
дату и время. Затем созданы три текстовые переменные header, value_title, value_upper,
Шаблоны в Django 171
Итак, у нас все готово для того, чтобы проверить работу тега с фильтрами в шаблонах
Django. Запустим локальный сервер разработки командой
python manage.py runserver
0 Шаблоны х + V
� ➔ С (D 127.0.0.1:8000
�\ Авиабметы О Яндекс � Перевести G Gmail
Фильтрь1 в шаблонах
• 4
• Пн 19 Дек 2022
• 09:49
• Это Прю1ер Использования Фильтров
• ЭТО СТРОКА В ВЕРХНЕМ РЕГИСТРЕ
блок объявлений
селектор описание описание
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<titlе>Привет Django</title>
</head>
<body>
<hl>Домашняя страница Django!</hl>
<h2>terrplates/firstapp/home.html</h2>
</body>
</html>
Откроем файл firstapp/views.py и изменим значение функции def index(), как показано в
листинге 6.21.
def index(request):
return render(request, "firstapp/home.html")
� ➔ С (D 127.0.0.1:8000
<!ООСТУРЕ html>
<html lang="en">
<head>
<style>hl{color: red;}</style>
<style>h2{color: Ыuе; font-size: 22px;}</style>
<meta charset="UTF-8">
<titlе>Привет Django</title>
</head>
<body>
<hl>Домашняя страница Django!</hl>
<h2>teпplates/firstapp/home.html</h2>
</body>
</html>
Здесь мы в стилях для тегов <hl> задали красный цвет, а для тегов <h2> - синий цвет
и размер шрифта 22 рх. Снова обратимся к странице templates\firstapp\home.html и теперь
получим следующий результат (рис. 6.33).
� ➔ С (D 127.0.0.1:8000
Как видно из данного рисунка (при выводе цветного изображения на экран компьюте
ра), цвета вьmодимого текста поменялись: первая строка выведена красным цветом,
а вторая- синим.
Встроенные cmWtu отличаются от внутренних стилей тем, что они встраиваются в тело
<Ьоdу> НТМL-документа, при этом стили встраиваются в другие теги. Изменим текст
файла templates\firstapp\home.html, как показано в листинге 6.23.
<!ООСТУРЕ html>
<html lang="en">
<head>
<style>hl{color: red;}</style>
<style>h2{color: Ыuе; font-size: 22px;}</style>
<meta charset="UTF-8">
<titlе>Привет Django</title>
</head>
<body>
<hl style= "color: grееn">Домашняя страница Django!</hl>
<h2 style="color: red">templates/firstapp/home.html</h2>
</body>
</html>
Здесь мы в теге заголовка <head> для текста с тегами hl оставили красный цвет, с тегами
h2 - синий. Однако в теле НТМL-страницы <Ьоdу> переопределили эти цвета с исполь
зованием встроенных стилей. Для заголовка hl задали зеленый цвет, а для заголовка
h2 - красный. Обратите внимание, что стили встроены непосредственно в теги hl и h2.
Снова обратимся к странице templates\firstapp\home.html и теперь получим следующий
результат (рис. 6.34).
0 Привет Django х + V
� ➔ С (D 127.0.0.1:8000
Теперь используем этот файл в шаблоне. Для этого в начале файла шаблона необходи
мо определить инструкцию:
{% load static %}
Шаблоны в Django 177
Вложенные пamrn
JICIIIQ .___.J Файлы
• WII�
-init_.py
asgi.py
-init_.py
] -init_.py
admin.py
�
settings.ру apps.py
1
urls.py
.,
models.py
tests.py
1
index.html ]
,index_appl.html
manage.py _ 1
Рис. 6.35. Структура проекта hello после добавления в него папок для размещения статичных файлов
Рис. 6.36. Вход в режим создания нового файла в папке для таблиц стилей css
178 Глава б
Рис. 6.37. Задание имени новому файлу в папке для таблиц стилей css
/Г'
i [iiJ Project .,, ЕЭ + j О - il, settings.py Х � е1. hon
f �Cl!IWeЬ_J. O\Users\Vit\Py�harniP, 1 1 /' static/ш/styles.css •;
.:;, 2 j Ьоdу hl {color: red;}
T'II helfo ·
•J; : ;�;s;б= h> (,ощ, gc«,;}
Рис. 6.39. Место инструкций load static и link в файле шаблона home.html
Шаблоны в Django 179
<!DOCTYPE html>
{% load static %}
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Пpивeт'Django</title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
</head>
<body>
<hl>Домашняя страница Django!</hl>
<h2>Это шаблон из файла terrplates/firstapp/home.html</h2>
</body>
</html>
Как видно из данного рисунка, в шаблоне присутствует тег {% load static %}, загру
жающий в шаблон URL-aдpec хранилища, в котором находятся статические файлы. Для
определения пути к статическим файлам в шаблоне используются выражения типа:
{% static "путь к файлу внутри папки static" %}
Так как мы будем размещать СSS-файлы в папке css/styles.css, то этот тег у нас выглядит
следующим образом:
{% static 'css/styles.css' %}
Тег <link> (от англ. link - ссылка, связь) устанавливает связь с внешним документом
вроде файла со стилями или изображениями. Атрибут rel="stylesheet" указывает, что
этот файл является таблицей стилей. Таким образом, для href мы фактически задали
путь к СSS-файлу.
Чтобы файлы из папки static могли использоваться в приложениях, нужно указать путь
к этой папке в файле settings.py, добавив в конец файла код из листинга 6.26, как показа
но на рис. 6.40.
STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static"),
0 Привет Django х + а.
< с 00
00
ПРИМЕЧАНИЕ
В некоторых версиях Google Chrome могут возникнуть проблемы с использованием под
ключенных СSS-файлов. Если у вас в Google Chrome вместо цветного текста на этой стра
нице появился текст в черно-белом цвете, то попробуйте загрузить ее в браузер Орега.
Как видно из данного рисунка (при вьmоде цветного изображения на экран компьюте
ра), в соответствии со стилями, указанными в файле styles.css, текст тега hl выделен
красным цветом, а текст тега h2 - зеленым. При этом в самом НТМL-файле стили для
выделения текста каким-либо цветом не указаны, а лишь сделаны ссьmки на файл со
стилями. Такой подход очень удобен тем, что можно оперативно менять и настраивать
стили на десятках станиц сайта, внося изменения в код всего одного файла.
Изображения тоже являются статическими файлами. Для хранения изображений мы
ранее создали папку images. Разместим в этой папке файл с любым изображением и да
дим ему имя image1 .jpg. Теперь выведем его на нашей странице templates/firstapp/home.html,
для чего модифицируем код страницы, как показано в листинге 6.27.
<!DOCTYPE html>
(% load static %}
<html lang="en">
Шаблоны в Django 181
<head>
<meta charset="UTF-8">
<titlе>Привет Django</title>
<link href="{% static 'css/styles.css' %}" rel="stylesheet">
</head>
<body>
<hl>Домашняя страница Django!</hl>
<h2>teпplates/firstapp/home.html</h2>
<img src="{% static 'images/imagel. jpg' %}">
</body>
</html>
о. l=l&IIEII
0 Привет Djan90 х +
< с □□
□о (§) 127.0.0.1:8000
image1 .jpg. Однако для выводимых на НТМL-страницах рисунков в файле styles.css тоже
можно указывать стиль отображения. Изменим файл styles.css, как показано в листин
ге 6.28.
/* static/css/styles.css */
body hl {color: red;)
body h2 {color: green;)
img{width:250px;)
Здесь мы указали, что ширина изображения должна быть 250 пикселов. После такого
изменения страница home.html будет выглядеть, как показано на рис. 6.43.
= @)
0 Р"Бе Django х +
< с 00
00
Как можно видеть из данного рисунка, то же изображение из файла image1 .jpg на НТМL
странице имеет другой размер, который соответствует стилю, указанному в файле
styles.css.
шаблон для генерации ответа. Кроме того, при необходимости представление может
обратиться к БД и вставить в шаблон некоторые данные из нее. Однако если нужно
просто возвратить пользователю содержимое шаблона, то для этого необязательно
определять функцию в представлении и обращаться к ней. Можно воспользоваться
встроенным классом TerrplateView и вызвать нужный шаблон, минуя обращение к пред
ставлению.
На рис. 6.44 показан вариант приложения, в котором шаблон главной страницы сайта
home.html вызывается функцией из представления view, а шаблоны страниц about и contact
вызываются с использованием класса TerrplateView.
Интернет- НТТР-запрос
НТТР-ответ
nоль1ователь Response (НTh,1L)
!._
Request
r1 p�'a1:юutl', TemplateView.as_vie-1�•(temp!ate_name="aЬout.html") }
1 g_cl' inde.x(request):
�мn render(re.quest, "firstapp/home.html")
j�
1,
home.html
1
� rontact.hlml
1
.� aЬout.html
1
Шаб,1овы (remplates\firstapp\)
Проверим, как это работает на простых примерах, для этого создадим несколько про
стейших шаблонов в папке hello\templateslfirstappl. Пусть это будет файл-шаблон about.html
с кодом из листинга 6.29.
184 Глава б
<!ООСТУРЕ htпй>
<htпй lang="en">
<head>
<meta charset="UTF-8">
<titlе>Привет Django</title>
</head>
<body>
<hl>Контактные данные компании</hl>
<h2>" Интеллектуальные информационные системы "</h2>
<hЗ>Адрес: г. Москва, ул. Короленко, д. 24</hЗ>
<h4> Это шаблон из файла templates/firstapp/contact.htпй</h4>
</body>
</htпй>
urlpatterns = [
path(' ' , views.index),
path('aЬout/', TemplateView.as_view(template_name="firstapp/about.htпй")),
path('contact/', TemplateView.as_view
(template_name="firstapp/contact.htпй")),
]
def index(request):
return render(request, "firstapp/home.html")
Затем в двух строках программного кода, приведенных в листинге 6.3 1, для вызова
страниц firstapp\about.html и firstapp\contact.html используется класс Terrq:JlateView:
path('aЬout/', TerrplateView.as_view(teпplate _name="firstapp/aЬout .html")),
path('contact/',TerrplateView.as_view(teпplate_name="firstapp/contact.html")),
urlpatterns = [
path(' ', views. index),
path( 'aЬout/', TeпplateView. as_view(terrplate_name="firstapp/aЬout .html")),
path('contact/', TerrplateView.as_view(teпplate_name=
"firstapp/contact.html",
extra_context={"work":
"Разработка программных продуктов"}}),]
Здесь в шаблон contact.html передается объект work, который представляет строку со сле
дующей информацией: "Разработка программных продуктов". И теперь мы можем использо
вать этот объект в шаблоне firstapp/contact.html (листинг 6.33).
<!DOCTYPE html>
<html lang="eп">
<head>
<meta charset="UTF-8">
<titlе>Привет Django</title>
</head>
<body>
<hl>Контактные данные компании</hl>
<h2>"Интеллектуальные программные системы"</h2>
186 Глава б
О 0 Приоет Django х + Q.
< ) С 88 0 127.0.0.1:8000
О 0 Приоет Django Q.
о
Сведения о компании
Ф "Интеллектуальные информационные системы"
�-• Это шаблон нз файла templates/firstapp/about.html
с::, @1
О 0 Приоет Django х + Q.
о
Контактные данные компании
Ф " Интелле1...уальные информационные системы "
о Адрес: г. :Моtю1а, )'д. Короденко, д. 24
в
Рис. 6.45. Примеры обращения к шаблонам НТМL-страниц с использованием представления view (а)
и класса TenplateView (б и в)
Шаблоны в Django 187
О 0 При•� Django
( ) С 88 С 127.Ml:8000/contact � @] ® }> <:? ,i d. _
о
Контактные данные компании
Ф " Интеллектуальные информационные системы "
о Разработка програl\1мн.ых продуктов
В этой инструкции текущий шаблон расширяет базовый шаблон base.htm. Иными слова
ми, при помощи тега extenct мы указываем, какой шаблон мы будем расширять или
уточнять.
Рассмотрим пример создания структуры сайта на основе базового шаблона и несколь
ких дочерних шаблонов НТМL-страниц (рис. 6.47).
Как видно из данного рисунка, в структуре сайта есть базовый шаблон base.html, кото
рый может быть расширен за счет дочернего шаблона. В свою очередь, этот дочерний
шаблон можно расширить за счет других шаблонов. Попробуем сформировать струк
туру сайта с использованием тегов Ыосk и extenct.
Шаблон страницы base.html может иметь следующую структуру:
{% Ыосk head %)
{% Ыосk title %){% endЫock %)
{% Ыосk menu %){% endЫock %)
{% endЬlotk %)
Шаблоны в Django 189
{% Ыосk page %}
{% Ыосk content %}
{% endЫock %}
{% endЫock %}
{% Ыосk footer %}
{% Ыосk copyright %}
{% endЫock %}
{% endЫock %}
Созданные на основе этого кода блоки могут быть расположены на НТМL-странице
так, как показано на рис. 6.48.
title
81!,R\I
% Ыосk title %}{% endЫock %}
{% Ыосk menu %}{% endb1ock %}
{.% endЬlock %}
..------,---
{% Ыосk page %}
{% Ыосk content %}
{% endЫock %}
{% endЬlock %}
{% Ыосk footer %}
{% Ыосk copyright %}
{% endЬlock %}
{% endЫock %}
copyript
Этот базовый шаблон теперь может быть расширен на основе другого шаблона с по
мощью следующего кода:
{% extend "base.htm" %}
{% Ыосk page %}
{% Ыосk content %}
{% endЫock %}
{% Ыосk sidebar %}
{% endЬlock %}
{% endЬlock %}
Здесь в первой строке указано, что это дочерний шаблон, который расширяет базовый
шаблон с именем base.html:
{% extend "base .htm" %}
Следующие строки говорят о том, что в базовом шаблоне блок с именем page, будет
заменен содержимым блока page из дочернего шаблона (рис. 6.49).
u
190 Глава 6
1
1 -
titц 1
1
content sideЬ•r {% extend "base.htm" %}
{% Ыосk page %}
-� {% Ыосk content %}
{% endЬlock %}
-
� {% Ыосk sidebar %}
{% endЬlock %}
{% endЬlock %}
·:1,
1
•'
�opyrijflt
Эту цепочку наследования можно продолжать сколько угодно, каждым новым дочер
ним шаблоном расширять один из родительских шаблонов. Перейдем от теории к прак
тике и создадим сначала фрагмент сайта на основе нескольких «скелетных» шаблонов,
а потом «украсим» эти шаблоны за счет возможностей фреймворка Bootstrap.
меняется в зависимости от того, какая страница сайта бьmа загружена в текущий мо
мент. Схематично взаимодействие шаблонов приведено на рис. 6.50.
Здесь base.html - базовый (родительский) шаблон, остальные страницы сайта - это
дочерние элементы, которые будут своим содержимым дополнять блок с контентом
базового шаблона. Базовый шаблон может иметь другую структуру и иной набор эле
ментов, например, может присутствовать «карусель» в верхней части страницы, правая
боковая панель, группа раскрьmающихся элементов типа «аккордеон» и т. п.
Ьase.html
Ы>КОЕЗJI
Конrенr
панель Конrенr
contact.html
Коиrеиr
<!DOCTYPE html>
<html lang="en">
192 Глава 6
<head>
<meta charset="UTF-8">
<title>{% Ыосk title %}{% endЫock title %}</title>
</head>
<body>
<hl>Логотиn и Заголовок сайта</hl>
<h4>Главная страница О комnании Контакты</h4>
<div>{% Ыосk header%}{% endЫock header %}</div>
<div>{% Ыосk content%}{% endЫock content %}</div>
<h5>Подвал (footer) сайта</h5>
</body>
</html>
Ьase.html
Лоrопm Заголовок сайrа (Ьеаd)
1ndex.html
Верхиее меню (menu)
Конrе:нr
aЬout.html
Контенr (content)
Конrеиr
contact.html
и закрьmающий элемент:
{% endЫock название_блока %}
Для каждого блока можно задать содержимое по умолчанию, самих же блоков в шаб
лонах может быть сколько угодно.
В базовом шаблоне также определены следующие неизменяемые элементы: логотип
компании и заголовок сайта, главное меню, подвал страницы (tooter). Поскольку эти
элементы будут общими для всех страниц, то мы не обрамляем их блоками, а задаем им
значения в виде констант.
Теперь сформируем дочернюю страницу и расширим наш базовый шаблон. Создадим
в каталоге templateslfirstapp новый файл-шаблон главной страницы сайта с именем
index.html и напишем в нем код из листинга 6.35.
{% extends "firstapp/base.html" %)
{% Ыосk title %)Главная страница{% endЫock title %)
{% Ыосk header %)Это главная страница сайта - index.html. {% endЬlock header %)
{% Ыосk content%)
Это содержимое блока content. Этот текст находится на странице index.html,
но он вставлен в базовый шаблон - base.html в блок с именем context.
{% endЬlock content %)
def index(request):
return render{request, "firstapp/index.html")
Здесь в функции inctex () в качестве домашней страницы сайта указан файл firstapp/
index.html.
Если после этих изменений запустить локальный веб-сервер
python manage.py runserver
и перейти на главную страницу bttp://127.0.0.1:8000/, то мы увидим следующий ре
зультат (рис. 6.52).
Как видно из данного рисунка, страница index.html является дочерней страницей базового
шаблона. При этом постоянные элементы базового шаблона не изменились, а в блоки
title, heacter и content был вставлен текст из соответствующих блоков дочернего шабло
на. Обратите внимание, что в коде страницы index.html нет ни одного фрагмента, напи
санного на языке НТМL, при этом содержание этой страницы успешно вьmедено в окно
браузера.
194 Глава 6
l=l@JI zg 1
0 + V
� ➔ С ф 127.0.0.1:8000
Теперь для того же базового шаблона base.html сформируем другую страницу сайта -
firstapp/about.html. Эта
страница уже существует, т. к. она была создана в предыдущих раз
делах. Удалим содержимое этой страницы и напишем в ней программный код, приве
денный в листинге 6.37.
{% extends "firstapp/base.html" %}
{% Ыосk title %}О компании{% endЫock title %}
{% Ыосk header %}Сведения о компании{% endЫock header %}
{% Ыосk content %}
Компания "Интеллектуальные информационные системы".
Наша компания занимается разработкой приложений,
основанных на системах компьютерного зрения
и искусственного интеллекта, кросс-платформенных настольных
мобильных приложений, а также веб-приложений
с использованием языка программирования Python.
Это содержимое блока content. Этот текст находится на
странице aЬout.html, но он вставлен в базовый
шаблон - base.html, в блок с именем context.
{% endЫock content %}
Теперь файл firstapp/urls.py должен выглядеть так, как показано в листинге 6.38.
Далее нужно в файле firstapp/views.py создать функцию aЬout(). Программный код файла
firstapp/views.py к
данному моменту должен выглядеть так, как показано в листинге 6.39.
"firstapp/aЬout.html")
�х + V
� ➔
-�
С CD 127.0.0.1:8000/about/
�-
Рис. 6.53. Страница сайта about.html, которая является расширением базового шаблона base.html
196 Глава 6
{% extends "firstapp/base.html" %)
{% Ыосk title %)Контакты{% endЫock title %)
{% Ыосk header %)Контактные данные.{% endЫock header %)
{% Ыосk content %)
Компания "Интеллектуальные информационные системы".
Адрес: г. Москва, ул. Короленко, д. 24
тел.: +7 999 999 99
e-mail: iis@yandex.ru
Это содержимое блока content. Этот текст находится
на странице contact.html, но он вставлен в базовый
шаблон - base.html, в блок с именем context.
{% endЫock content %)
Теперь нужно в файле firstapp/views.py создать функцию contact{). Программный код фай
ла firstapp/views.py к данному моменту должен выглядеть так, как показано в листин
ге 6.42.
def aЬout(request):
return render(request, "firstapp/aЬout.html")
clef
st, "firstapp/contact.htinl")
х +
� ➔ С (D 127.0.0.1:8000/contact/ <Э. t.e * □ �
-.:"i Авиабметь, О Яндек.с Qi: Перевести G Gmail
Кояrакrные данные.
ом:паНШ! "Интеллекrуа:п.ные информационные системы". Адрес: r .
Москва, ул. Короленко, д . 2 4 тел.: + 7 999 999 99 e-mail: iis@yandex.ru
Это содержимое бдока content. Этот текст находится
на странице contact.httn!, но он всrав.,,еи в базовый шабаон - base.html в
блок с именем context.
Блoк
ll<ЩШ1n (foot,r) еаiта content
Рис. 6.54. Страница сайта coпtact.html, которая является расширением базового шаблона base.html
Итак, мы создали базовый шаблон и три страницы сайта, которые являются расшире
нием базового шаблона. Подводя итоги этого раздела, отметим, что на основе базового
шаблона можно создавать разные страницы сайта, с общими элементами и блоками,
в которых можно размещать разную информацию.
В базовом шаблоне есть меню, состоящее из трех опций: «Главная страница», «О ком
пании» и «Контакты». Однако в меню не прописаны ссылки для того, чтобы по ним
можно бьmо перейти на соответствующие страницы. Давайте рассмотрим, как в шаб
лонах Django реализована адресация на другие шаблоны (фактически на другие веб
страницы).
Однако проставлять прямые ссьшки на страницы сайта- это не лучший вариант. Се
годня ваш сайт находится в разработке на вашем компьютере по адресу: 127.0.0.1:800,
завтра он будет развернут на сервере по адресу (доменному имени): mysite.ru. Если ста
вить полные пути до страниц (например, 127.0.0.1/catalog/books), то при каждом переезде
сайта придется менять все ссылки во всем проекте. Чтобы избежать таких ситуаций,
в шаблонах Django для создания ссьшок предусмотрен специальный тег, который имеет
следующий синтаксис:
{% url 'url-name' vl v2 %}
Здесь первый аргумент- имя шаблона URL (url-name). Это может быть заключенный
в кавычки литерал или любая другая контекстная переменная. Дополнительные аргу
менты (vl, v2) являются необязательными и должны представлять собой значения, раз
деленные пробелами, которые будут использоваться в качестве аргументов в URL.
Имена ссьшок 'url-name' можно указать в файле urls.py. Они передаются как параметр
name при создании пути (path), например:
path (", views.index, name='index')
Как видно из данного листинга, главной странице сайта задано имя name='index', стра
нице «О компании»- name=' aЬout', странице «Контакты»- name='contact'.
Теперь изменим базовый шаблон (файл templates/firstapp/base.html). Изменения, внесенные
в код этого файла, приведены в листинге 6.44 (выделены серым фоном).
<!ООСТУРЕ html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{% Ыосk title %}{% endЬlock title %}</title>
</head>
<body>
<hl>Логотил и Заголовок сайта</hl>
Шаблоны в Django 199
<h4>
r
1 index' f ''>l'.пa&IWI 7', �
1 aooiit 1 \J ">0 компании</�
'contact' \}"Жоитакrrы<7�
</h4>
<div>{% Ыосk header%}{% endЬlock header %}</div>
<div>{% Ыосk content%}{% endЫock content %}</div>
<h5>Подвал (footer) сайта</h5>
</body>
</html>
Эта строка бьmа разбита на три строки и с использованием тега { % url 'name') были соз
даны ссьmки на шаблоны страниц: index (Главная страница), aЬout (О компании) и
contact (Контакты). После этих изменений переходить между станицами сайта можно
через меню, которое находится в базовом шаблоне.
Если после этих изменений запустить локальный веб-сервер
python manage.py runserver
0 Главная страница х V
f- ➔ С ф 127.0.0.1:8000
Рис. 6.55. Главная страница сайта с меню, которое находится в шаблоне base.html
Как видно из данного рисунка, на странице появилось меню. Каждая опция меню
выделена подчеркиванием и синим цветом. Теперь переключаться между страницами
сайта можно через меню, которое присутствует на каждой странице, при этом оно фак
тически размещено в базовом шаблоне.
Итак, с помощью шаблонов мы создали простой сайт, состоящий из трех страниц.
Шаблоны Django позволяют достаточно быстро и просто формировать технологиче
скую часть веб-приложения, но, если вы обратили внимание, все страницы выполнены
200 Глава 6
INSTALLED APPS
# ...
"Ьootstrap5",
# ...
<!DOCTYPE html>
<html lang= "en">
<head>
{% load static %}
<meta charset="UTF-8">
<meta name="viewport" conte 1">
-"--��---
<link rel="stylesheet" hrej'
<script defer src="/static/'
<title>{% Ыосk title %}{% endЫock title %}</title>
</head>
<body>
<div class= "container-fluid р-1 bg-primary text-white text-center">
<div class="row">
<div class="col-2 ">
<img src= "{% static 'images/SIS. jpg' %} ">
</div>
<div class="col-10 ">
<hl>Это заголовок главной страницы сайта</hl>
</div>
</div>
</div>
<div class= "container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="{% url 'index' %}">Главная страница</а>
<а href= "{% url 'aЬout' %}">О комnании</а>
<а href="{% url 'contact' %}">Контакты</а>
</hб>
</div>
</div>
202 Глава 6
,,С +
f-· � (J ф ll1�
1\� О"-"<.,.,._ GC.-,
� ➔ С ф 127.��
"'� Oa...i,c --� GG,,...
Контактнь1:е данные.
Кoo,t..'ljw�• ..,.�- 11•00S:,w_н,_ a>Cf1!., , � t. � �
�""'- 4- 2<!,u,; •1991999999.,_rr, аsф� Эr0>CQ11--�<<><ll1N1t
Э.01 fКСТ � щC'fUн'1if -l'.1111\L"" c.. w-• 6uuw� uuO,..C..
Ь.И.Ыml 1 6.юк t ,......,.,, cO<l'l«J:L
Рис. 6.57. Страницы сайта после подключения в базовый шаблон тегов Bootstrap
Шаблоны в Django 203
<div class="container-fluid">
<div class="row text-center text-primary fs-1 fw-bold">
<div>{% Ыосk header%){% endЫock header %)</div>
</div>
<div class="row text-center text-body">
<div>{% Ыосk content%){% endЫock content %)</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-primary text-center text-white lh-1">
<р>Это nодвал (footer) страниц сайта</р>
</div>
</div>
</body>
</htrnl>
Тег now позволяет вьmести системное время и дату. В качестве параметра тегу now пере
дается формат данных, который указывает, как форматировать время и дату. Символы
для форматирования времени и даты приведены в табл. 6.1.
Все возможные форматы для вывода даты и времени можно посмотреть в оригиналь
ной документации на Django.
х +
* [) е,
V
� ➔ С ф 127.0,0.1:8000/аЬооt/ � !В
Рис. 6.58. Страница сайта aЬout.html (варианты вывода текущей даты и времени)
{% extends "firstapp/base.html" %}
{% Ыосk title %}Контакты{% endЫock title %}
{% Ыосk header %}Контактные данные{% endЫock header %}
{% Ыосk content %}
Компания "Интеллектуальные информационные системы"
<div class="container-fluid text-center my-2 border border-3">
<div class="row ">
<div class="col-sm-6 ">
<hЗ>Адрес</hЗ>
<р>г. Москва, ул. Короленко, д. 24</р>
</div>
<div class="col-sm-3 ">
<hЗ>Телефон</hЗ>
<р>+7 999 999 99</р>
</div>
<div class="col-sm-3 ">
<hЗ>e-mail</hЗ>
<p>iis@yandex.ru</p>
</div>
</div>
</div>
{% endЬlock content %}
0 Конт�кrы х +
f- ➔ С <D 127.0.0.1:8000/contact/
Контактные данные
г
Компания "Интеллектуальные информационные системы".
{% extends "firstapp/base.html" %}
{% Ыосk title %}Главная страница{% endЫock title %}
{% Ыосk header %}Это главная страница сайта - index.html.{% endЫock header %)
{% Ыосk content%)
Месяцы (поквартально)
<div class="container-fluid my-2 text-start">
<div class="row">
<div class="col-6 text-end">
{% for kv in my_kv %)
<div>{{ kv }}</div>
{ % endfor % )
</div>
<div class="col-6">
<div class="row">
{ % for пюnth in my_month %) ,
<div class="col-4">{ { month }}</div>
{% endfor %}
</div>
</div>
</div>
</div>
{% endЬlock content %}
Здесь создан контейнер, в который вложена одна строка, разбитая на две колонки.
В первой колонке с помощью тега организации цикла {% for kv in my_kv %) выводятся
четыре строки названий кварталов, а во второй колонке за счет тега организации цикла
{% for month in my_пюnth % J выводятся четыре строки с названиями месяцев каждого
квартала. Причем длинный список месяцев будет автоматически разбит на четыре
строки благодаря тегу <ctiv class="col-4">{{ month J J</div> фреймворка Bootstrap.
208 Глава 6
Теперь в этот шаблон нужно передать список с названиями кварталов (my_kv) и список
с названиями месяцев (my_month). Для создания этих списков откроем файл hello/firstapp
/views.py и изменим в нем функцию index, как показано в листинге 6.50.
def index(request):
my_kv = ['I квартал ->', 'II квартал ->', 'III квартал->',
'IV квартал->']
my_month = ['Январь', 'Февраль', 'Март',
'Апрель', 'Май', 'Июнь',
'Июль', 'Август', 'Сентябрь',
'Октябрь', 'Ноябрь', 'Декабрь']
context = { 'my_month': my_month, 'my_kv': my_kv}
return render(request, "firstapp/index.html", context)
В этом программном коде созданы два списка: my_kv - названия кварталов, my_month -
названия месяцев. Затем создан словарь context, в который включили два этих списка.
В последней строке в функции render словарь context передан в шаблон firstapp/index.html.
Все изменения сделаны. Если обратиться к странице contact.html после этих изменений,
то мы получим следующий результат (рис. 6.60).
Как видно из данного рисунка, список из 12 месяцев представлен на странице в виде
таблицы из 4 столбцов и 4 строк, хотя в программном коде отсутствуют теги для фор-
0 Главная страница х + V
� ➔ С (D 127.0.0.1:8000
-:( Аsиабилеты О Янде�а: Щ,, п"рееести G Gmail
мирования таблиц. Вся разбивка списка месяцев на столбцы и строки выполнена с ис
пользованием тегов <div> и классов фреймворка Bootstrap, а также за счет тегов органи
зации циклов { % for % ) фреймворка Django.
Формы
Форма НТМL - это группа из одного или нескольких полей (виджетов) на неб-стра
нице, которая служит для получения информации от пользователей для последующей
отправки на сервер и представляет собой гибкий механизм сбора пользовательских
данных. Формы несут целый набор виджетов для ввода различных типов данных: тек
стовые поля, флажки, переключатели, установщики дат и пр. Формы являются относи
тельно безопасным способом взаимодействия пользовательского клиента и сервера,
поскольку позволяют отправлять данные в РОSТ-запросах, применяя защиту от меж
сайтовой подделки запроса (Cross Site Request Forgery, CSRF). Из материалов этой гла
вы вы узнаете:
□ что такое формы Django и для чего они нужны;
□ как применять в формах РОSТ-запросы;
□ какие поля можно использовать в формах;
□ как можно выполнить настройку формы и ее полей;
□ как изменить внешний вид формы;
□ как осуществляется проверка (валидация) данных в формах;
□ как можно добавить стили к полям формы.
llEJ
Рис. 7.1. Поле формы для ввода ФИО клиента
1
212 Глава 7
объекты для генерации кода НТМL-формы для контроля над процессом валидации
и для других пользовательских взаимодействий с формой. Форма Django выполняет
три наиболее важные части работы, связанной с данными:
□ получение, реструктуризация данных и их подготовка к рендерингу (к визуали-
зации);
□ создание НТМL-форм для ввода данных;
□ получение и обработка данных от клиента и их запись в БД.
Весь этот код можно написать и вручную, но Django все это может сделать за вас. По
следовательность действий Django при работе с формами представлена на рис. 7.2.
Создать форму с
nольэо11ательскими
Отnрааить связанttv�о
данными и
форму ПОдЬЮIIВТеJНО
сообщениям и об
оwибкех
Пользователь Создать·
заполю:�ет или несвязанную
обновляет форму nо
форму умолчани�о
Да Сервер
эапрашив.ает
Проверка
страницу с
данных
формой
Страница с
Польэо11атель Перенаправить
успе шным
отает на
заверше нием
успешный URL
ввода данных данными
В соответствии с рис. 7.2 Django выполняет следующие операции при работе с фор
мами.
1. Показ формы по умолчанию при первом запросе со стороны пользователя.
• Форма может содержать пустые поля (например, если вы создаете новую запись
в базе данных), или поля могут иметь начальные значения (например, если вы
изменяете запись или хотите заполнить ее каким-либо начальным значением).
• Форма в текущий момент является несвязаююй, потому что она не ассоциируется
с какими-либо данными, введенными пользователем (хотя и может иметь на
чальные значения).
2. Получение данных из формы (из НТМL-формы) со стороны клиента и связывание
их с формой (классом формы) на стороне сервера.
214 Глава 7
После этого мо�о создавать собственные классы форм на основе следующей инструк
ции:
class NameForm(forms. Form)
Как видно из данной инструкции, каждая форма определяется в виде отдельного клас
са, который расширяет класс forms. Foпn. Классы размещаются внутри проекта, где они
используются. Как правило, они помещаются в отдельный файл, который можно
назвать, например, forms.py. Однако формы могут размещаться и внутри других, уже
имеющихся в приложении файлов, например в views.py или models.py. Чтобы не запутать
ся и четко знать, где находятся классы, описывающие формы, создадим для них от
дельный файл.
Для работы с формами воспользуемся сайтом, который был создан в предыдущей
главе. В проекте hello в папке с приложением firstapp. создадим новый файл
hello/firstapp/forms.py. В этом файле создадим нашу первую форму с именем userFoпn. Для
этого поместим в файл forms.py код из листинга 7.1, как показано на рис. 7.3.
Здесь класс нашей новой формы имеет имя userFoпn. В этом классе определены два
поля: name (имя) имеет тип forms.CharField- текстовое поле (input type="text"), поле age
(возраст) имеет тип forms. rntegerField- числовое поле (input type="nlli!IЬer"). Таким
образом, первое поле предназначено для ввода текста, а второе - для·ввода чисел.
Далее в файле views.py изменим код функции index () и напишем код для новой функции
my-form(). В итоге файл views.py будет выглядеть так, как показано в листинге 7.2 (изме
нения выделены серым фоном).
Здесь первым шагом был выполнен импорт созданного нами класса userForm. Затем был
изменен код функции inctex(), которая вызывает главную форму приложения. Здесь
убраны строки формирования списков кварталов и месяцев, которые были написаны
в последнем разделе главы 6, вместо них вставлена строка, которая будет оправлена
в шаблон главной формы приложения. Наконец, была сформирована новая функция
с именем my_form. В ней на основе класса userForm() создан объект - userform, фактиче
ски это и есть наша форма из файла forms.py. Через словарь context эта форма передана
в шаблон Django с именем my_form.html. Здесь созданный нами объект формы передается
в шаблон my_form.html через ключ словаря "form".
Создадим для нашей формы новый шаблон Django, это будет НТМL-файл с именем
hello/templates/firstapp/my_fotrm.html. Код этого файла приведен в листинге 7.3.
{% extends "firstapp/base.htrnl" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %}
<div class="container-fluid my-2 border border-3">
<tаЫе>
{ { form } }
</tаЫе>
</div>
{% endЬlock content %}
{% extends "firstapp/base.html" %)
{% Ыосk title %)Главная страница{% endЬlock title %)
{% Ыосk header %)Это главная страница сайта - index.html. {% endЬlock header %)
{% Ыосk content%)
<div class="i::ow">
<div class=''col text-center text-dark">
<div>{{ rny_text ) )</div>
</div>
</div>
</div>
{% endЬlock content %)
На главной станице сайта теперь будет выведена всего одна строка, переданная из
функции index () в словаре context по ключу rny_text.
Теперь изменим базовый шаблон hello/templates/firstapp/base.html - добавим в главное меню
сайта ссьmку, по которой можно вызвать нашу форму. Изменения, внесенные в базо
вый шаблон base.html, приведены в листинге 7.5 (изменения выделены серым фоном).
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %)
<rneta charset="UTF-8">
<rneta narne="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="/static/css/bootstrap.rnin.css" >
<script defer src="/static/js/bootstrap.bundle.rnin.js"></script>
<title>{% Ыосk title %){% endЬlock title %}</title>
</head>
<body>
<div class="container-fluid р-1 bg-prirnary text-white text-center">
<div class= "row">
<div class="col-2 ">
<irng src="{% static 'irnages/SIS. jpg' %}">
</div>
<div class="col-10 ">
<hl>Это заголовок главной страницы сайта</hl>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="{% url ' index' %}">Главная страница</а>
<а href="{% url 'rny_f
<а href="{% url 'aЬout' %}">О комnании</а>
<а href="{% url 'contact' %)">Контакты</а>
218 Глава 7
</hб>
</div>
</div>
<div class="container-fluid">
<div class="row text-center text-primary fs-1 fw-bold">
<div>{% Ыосk header%}{% endЬlock header %}</div>
</div>
<div class="row text-center text-body">
<div>{% Ыосk content%}{% endЫock content %}</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-priпiary text-center text-white lh-1">
<р>Это подвал (footer) страниц сайта</р>
</div>
</div>
</body>
</htrnl>
Теперь, когда пользователь в главном меню сайта выберет опцию «Форма», то по связ
ке {% url 'my_form' %} будет вызвана функция views.my_form, которая отобразит шаблон
my_fotrm.html.
Итак, были сделаны все шаги для того, чтобы «прописать» форму на нашем сайте. Если
после этих изменений запустить локальный веб-сервер
python manage.py runserver
и перейти на главную страницу Ьttp://127.0.0.1:8000/, то мы увидим следующий
результат (рис. 7.4 ).
Как видно из данного рисунка, в строке меню появилась ссылка, по которой можно
вызвать форму Django. Если активировать эту ссьmку, то будет выполнен переход на
шаблон страницы сайта с созданной нами формой (рис. 7 .5).
Формы 219
0 Главная страница х + V
� ➔ С ф 127.0.0.1:8000
__ 2я
n2--��
_.,.,,..
страница сайта
index.html.
Изучаем формы Django
Это подвал (footer) страниц сайта
+
*
х V
ф 127.0.0.1:8000/my_for... €\, !В □ е}
G Gmail
l N::::"'--
=�--�-=-
---�-�- ----�-=-,-,---·-
Это подвал (footer) страниц сайта
На этой странице сайта в поля, которые обрамлены рамками, пользователь может вво
дить свои данные, причем в поле Age можно ввести только цифровые данные, ввод
любого текстового символа будет заблокирован.
Следует заметить, что в модуле forms.py мы задали только идентификаторы полей name
и age и не указали метки полей (1аье1), которые должны вьmодиться на экран рядом
с этими полями. В Django эти метки генерируются автоматически. В частности, как
можно видеть, для наших двух полей бьши сгенерированы метки: Name и Age. По
умолчанию в Django в качестве метки берется имя поля, и его первый символ меняется
на заглавную букву. С одной стороны, такой прием избавляет программиста от допол-
220 Глава 7
нительного задания значения метки поля, но это не всегда удобно. Часто требуется за
давать более осмысленные и достаточно длинные значения для меток полей и на языке,
отличном от английского.
В Django имеется возможность задания метки для поля с помощью параметра label.
Немного изменим содержимое файла forms.py и добавим к полям метки, как показано
в листинге 7.7.
После этих изменений шаблон страницы my_form.html будет выглядеть как на рис. 7.6.
0 Формы х + V
f- ➔ С ф 127.0.0.1:8000/my_for... · е_, !В * □ е,
�, АаиабилеТЪJ О Яндекс Пере5е<:ти G Gmail
Во:sраст клиента:
'--------�
Это подвал (footer} страниц сайта
Рис. 7.6. Вид формы forms.py в окне браузера при явном определении меток полей
Кроме параметра label поля форм Django имеют еще ряд параметров, которые разра
ботчик может определять программным способом. На них мы остановимся более под
робно в следующих разделах.
{% extends "firstapp/base.html" %)
{% Ыосk title %)Формы{% endЫock title %)
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %}
<div class="container-fluid text-center my-2 border border-3">
<form method="POST">
{% csrf_token %}
<tаЫе>
{{ form } }
</tаЫе>
<input type="suЬmit" vаluе="Отправ ь" >
</form>
</div>
{% endЫock сопtепt %}
Здесь был добавлен стандартный элемент НТМL <form> с указанием метода отправки
данных на сервер, которые пользователь введет в поля формы. Различают два метода
отправки данных- GET и POST:
□ GET- отправляет данные на сервер через адресную строку (URL-aдpec);
□ POST- отправляет данные на сервер в теле НТМL-запроса.
Так как даннь1е в форме могут содержать конфиденциальную информацию, то в таких
случаях нужно использовать метод POST.
Затем в теле тега формы <form> помещен встроенный тег Django {% csrf_token %}, кото
рый позволяет защитить приложение от CSRF-aтaк, добавляя в форму сsrf-токен в виде
скрытого поля.
ПРИМЕЧАНИЕ
CSRF (Cross-Site Request Forgery, также XSRF) - опаснейшая атака, которая приводит
к тому, что хакер может выполнить на неподготовленном сайте массу различных действий
от имени других зарегистрированных посетителей.
В нижней части формы помещена кнопка для отправки содержимого этой формы на
сервер:
<input type= "suЬmit" vаluе="Отnравить" >
Данные, которые сервер получает из формы, служат для идентификации пользователей,
либо записываются в БД, либо являются параметрами для поиска информации в БД.
В примерах данной главы мы не будем реально оправлять данные на сервер, эти функ
ции будут рассмотрены в следующих главах, но эта кнопка будет задействована для
имитации отправки данных.
Все изучаемые нами поля мы будем размещать в коде файла forms.py.
222 Глава 7
Каждое поле, когда оно отображается на НТМL-странице, имеет типичный для него
внешний вид. Например, поле для ввода текста имеет обрамление в виде рамки. За
внешний вид полей отвечает виджет - визуальный элемент на НТМL-странице. Вид
жеты не следует путать с полями формы. Поля формы имеют дело с логикой проверки
ввода и используются непосредственно в шаблонах. Виджеты же имеют дело с отобра
жением (внешним видом) полей формы на веб-странице и извлечением необработан
ных отправляемых данных. Однако виджеты должны быть назначены полям формы.
Всякий раз, когда вы создаете поле в форме, Django задает виджет по умолчанию, со
ответствующий типу данных. Ранее рассмотренным полям при генерации разметки
соответствовали определенные виджеты из пакета forms. wictgets. Например, класс
CharField - виджет forms. widgets. Textinput, а класс ChoiceField - виджет forms.widgets.
select. Однако есть ряд виджетов, которые по умолчанию не связаны с полями форм,
но тем не менее мы можем их применять:
224 Глава 7
□ MultipleHiddeninput - генерирует
набор скрытых полей;
□ тextArea- генерирует многострочное текстовое поле: <textarea></textarea>;
□ Timeinput- генерирует поле для ввода времени (например, 12:41 или 12:41 :32);
□ SelectDateWidge - генерируеттри поля select для выбора дня, месяца и года;
□ SplitHiddenDateTimeWidget- использует скрытое поле для хранения даты и времени;
□ initial - определяет начальное значение для поля при его отображении на неза
полненной форме. Например:
name forms.CharField(initial= 'Beдитe ФИО')
=
□ widget - позволяет указать класс Widget, который следует использовать при отобра
жении поля вместо того, который задан по умолчанию;
□ help_text - описание данных, которые нужно внести в поле. Если вы укажете
он будет показан около поля при отображении формы с помощью вспомо
help_text,
гательных методов. Например:
suЬject = forms.CharField(max_length=l00,help_text='He более 100 символов')
sender = forms.EmailField(help_text='Bвeдитe email адрес')
Формы 225
Рис. 7.8. Ответ из формы после нажатия кнопки Отправить на странице my_fomi.html
В этом случае пользователь может либо поставить флажок в поле ьasket, либо оставить
его пустым, и приложение будет работать корректно.
Это поле служит для ввода текста. По умолчанию здесь используется виджет тextinput,
начальное значение которого - пустая строка (значение None) или текст, который был
задан в свойстве поля eщ:,ty_value.
Изменим модуль forms.py и создадим там это поле с помощью кода листинга 7.11.
Формы 227
Не забьmаем, что в таком варианте по умолчанию это поле будет обязательным для за
полнения. Если пользователь оставит его пустым, то при нажатии на кнопку Отпра
вить ему будет выдано напоминание, и программа не даст продвинуться вперед до тех
пор, пока поле не будет заполнено. Если логикой программы допускается оставить это
поле пустым, то его нужно создавать с помощью следующего программного кода:
name = forms.CharField(label="Имя клиента", required=False)
Число символов, которые пользователь может ввести в поле CharField, можно задать
с помощью следующих аргументов:
□ max_length - максимальное число символов в поле;
□ min_length - минимальное число символов в поле.
Например, мы можем создать это поле с помощью такого кода:
name = forms.CharField(label="Имя клиента", max_length=l5,
help_text="ФИO не более 15 символов")
В этом случае пользователь не сможет внести в поле более чем 15 символов, и рядом
с полем появится дополнительная подсказка. Внесем изменение в модуль forms.py (лис
тинг 7.12).
Имя клиента:
ФИО не более 15 символов
1 Отправить j
Поле choiceField служит для выбора данных из списка и по умолчанию использует вид
жет select с пустым значением None.
Поле имеет структуру forms. ChoiceField(choises=кopтeж_кортежей) и генерирует список
select, каждый из элементов которого формируется на основе отдельного кортежа. На
пример, поле
forms .ChoiceField(choices=((1, "Английский"),
(2, "Немецкий"),
(3, "Французский")))
_ _1 �:Тnравмть 1
Это подвал (footer) страниц сайта
Если пользователь нажмет левую кнопку мыши в этом поле, то откроется список для
выбора одного из языков (рис. 7.12).
Поле DateFielct служит для ввода дат (например, 2021-12-25 или 25/12/2021) и по умолча
нию использует виджет Dateinput с пустым значением None. При этом делается проверка,
является ли введенное значение либо строкой ctatetime. ctate, либо датой в определенном
формате. Поле принимает один необязательный аргумент input_formats.
Изменим модуль forms.py и создадим там поле для ввода даты с помощью кода лис
тинга 7.14.
�---,=,
8В41АИТ4t Аату: 1 .-1
О=т=п=ра=в=и=ът 1
Это подвал (footer) страниц сайта
Поле DateTimeField служит для ввода даты и времени (например, 2021-12-25 14:30:59 или
25/12/2021 14: ЗОJ и по умолчанию использует виджет oateTimeinput с пустым значением
None. При этом делается проверка, является ли введенное значение либо строкой
....
datetime .datetime, datetime.date, либо значениями даты и времени в определенном фор
мате. Поле имеет один необязательный аргумент input_formats.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.15 .
__J
L._в_в_41А_ит_•_А_ату_и_в_ре_м_
т
j Опра�ить J
_я :��::::::::����
��- .�- -1
Это подвап (footer) страниц сайта
Поле DecimalField служит для ввода десятичных чисел и по умолчанию использует вид
жет NumЬerinput с пустым значением None. При этом делается проверка, является ли вво
димое число десятичным.
Поле принимает пять необязательных аргументов:
□ max_value - максимальное значение вводимого числа;
□ min_value - минимальное значение вводимого числа;
□ max_whole_digits - максимальное число цифр (до десятичной запятой плюс после
десятичной запятой, с разделенными начальными нулями), допустимое в значении;
□ decimal_places - максимально допустимое число знаков после запятой;
□ step_size - шаг изменения введенного значения поля с использованием стрелок
прокрутки.
Сообщения об ошибках, выдаваемые при выходе вводимого значения за пределы
max_value и min_value, могут содержать тег % (limit_value) s, замещаемый соответствую
щим пределом. Аналогично сообщения об ошибках при выходе вводимых значений за
пределы, определяемые параметрами max_digi ts, max_decimal_places и max_whole_digits,
могут содержать тег % (max) s.
Когда курсор мыши находится в данном поле, то в правой его части появляются стрел
ки прокрутки. Нажимая на верхнюю или нижнюю стрелку левой кнопкой мыши, можно
увеличивать или уменьшать значение, введенное в данное поле. С помощью аргумента
step_size (размер шага) можно указать число, на которое будет меняться значение вве
денного числа.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.16.
�л и 1
Изучаем формы Django
--- -- · · •· к
Вве,111ите t11,есяти11иое 11исло: 1100
1 Отправить 1
< "..,
к
� про рутки fJ
l
ё,то подвал (footer) страниц сайт а
аргументов. Чтобы показать это, изменим программный код и укажем, что дробная
часть числа ограничена двумя знаками (листинг 7.17).
Если теперь в поле DecimalFielct попытаться ввести число с более длинной дробной
частью, то будет выдано предупреждение об ошибке ввода (рис. 7.16).
� �а Qкомпанми Ксжта�а-ы
Изучаем формы Django
� Кс»ФJЮ:Ы
_"!_-_----�
ав т
�1 О_т_п_р= и
= = _=ь
Это подвал (footer) страниц айта
с
.ЯЬiRIIPOloМЯIМ!fdll Кgмтмn,,
L , __ __
В Адрес элеюронноii nочты должен
сод ержать симв ол •�•. В адресе
'anatoly" отсутствует символ·@•.
Рис. 7.19. Подсказка об ошибке при вводе электронного адреса в поле EmailField
Как можно видеть из данного рисунка, поле FileFielct представлено в виде кнопки
с надписью «Выберите файл» и сообщением «Файл не выбран». Если теперь нажать
на кнопку Выберите файл, то откроется новое окно, в котором можно перемещаться
по любым папкам- компьютера, просматривать и выбирать произвольные файлы
(рис. 7.21 ).
■
8 Бибпиотеrи
•
Видю
li] Ho1ыii проект на Dj.ango.docx
Кпкс...dосх
14.12.2022 12:22
07.12.2022 8:10
До�_, ,;;,;\
'!Ш Г111111 З.dосх 06.12.2.0229:48
• ИюбJ№UНКА
� Пок.u PDF �Й/101 1 web.docx
Jt
Му,ыu
30.11.2.02211:37
11 Aмtnlv .,, ◄ --...-----.111 ::...---.-.....,..�в
Имя �Й/1.: 1Сп1ссы.dосх .. [ВсефllМы('.") •J
1 Оrкрыть :В '"- От- J
.f!
Рис. 7.21. Возможность выбора файла из окна ОС Windows при активации поля FileField
Предположим, что бьш выбран файл Классы.dосх и нажата кнопка Открыть, - окно
Windows будет закрыто, а имя выбранного файла показано на веб-странице (рис. 7.22).
Изучаем формыВыбра11ный
о·апgо
Ф11йп:I Выберите файл I Классы.dосх ..........,._....
_,ь.....�
1 Отправить 1
Рис. 7.22. Поле FileField на странице my_fom,.html после того, как пользователь выбрал файл
пр авить 1
__ [От
Это подвал (footer) страниц сайта
Если мы теперь щелкнем мышью на этом поле, то откроется список файлов, которые
содержатся в указанном каталоге. Пользователь будет иметь возможность выбора
любого файла из предложенного списка (рис. 7.24).
Внесем еще одно изменение в модуль forms.py, с помощью которого реализуем возмож
ность отображать в поле FilePathField не только файлы, но и вложенные каталоги (лис
тинг 7.22).
/ allow_files="True",
allow_folders="True")
Если теперь запустить наше приложение, то мы увидим, что кроме файлов у нас появи
лась возможность выбора и каталогов (рис. 7.25).
-.о.,,... �
Изучаем формы Django
Введение.dосх
Глава l.docx
Глава 2.docx
Оmра1мт1,
! .1-
-·· -=-_]
1 1 IP аАрес: �------�
! Пример формата 192.0.2.0
j Отправить 1
_
Это подвал (footer) страниц ta,iтa
gg��--.
� Оrкрыn, iii1
-Б- _ _ _ _ - - - �� а,к--н-�
► иблиотеки ► Изобр е ия ► -----"-i,,-�,_. � Поиск:Изобро:же,щ.11
! Открьпь /
Предположим, что был выбран файл АР_400.png и нажата кнопка Открыть, - окно
Windows будет закрыто, а имя выбранного файла показано на веб-странице (рис. 7.30).
� � QJCOМDiWtVil Конtцты
Поле IntegerField служит для ввода целых чисел и по умолчанию использует виджет
NumЬerinput с пустым значением None. При этом делается проверка, является ли вводимое
Формы 241
число целым. Поле принимает два необязательных аргумента для проверки максималь
ного (max_value) и минимального (min_value) значений вводимого числа и использует
методы MaxValueValidator и MinValueValidator, если эти ограничения заданы.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.26.
Если в поле IntegerFielct попытаться ввести число с дробной частью, то будет выдано
предупреждение об ошибке ввода (рис. 7.32).
�====':':":'С==::::'_�
Введите целое цисло: 12.34
Рис. 7.32. Предупреждение об ошибке при вводе в поле IntegerField числа с дробной частью
Д.ииые формата
JSON:
fi
Обратите внимание на правый нижний угол поля, там имеется специальная метка для
изменения размера поля ввода. Если данную метку «зацепить» с помощью левой кноп
ки мыши, то можно уменьшать или увеличивать размер поля, что обеспечит более
удобный ввод большого количества данных формата JSON.
Конечно, метод JSONField в большинстве случаев не очень удобен для рядовых пользо
вателей, однако это полезный способ форматирования данных из виджета на стороне
клиента для отправки на сервер, который вполне подходит для квалифицированных
разработчиков.
Формы 243
Поле генерирует список select на основе кортежа, как и поле foпns.ChoiceField, добавляя
к создаваемому полю атрибут multiple="multiple" и обеспечивая тем самым поддержку
множественного выбора.
По умолчанию поле MultipleChoiceField использует виджет SelectMultiple с пустым зна
чением [ J (пустой список), а также - как и поле ChoiceField - принимает один допол
нительный обязательный аргумент choices.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.28.
Как можно видеть из данного рисунка, в поле одновременно вьmодится весь список,
и пользователь имеет возможность выбрать из него несколько элементов. Для этого
необходимо поочередно щелкнуть мышью на нужных элементах списка, удерживая
при этом нажатой клавишу <Ctrl>, - выбранные пользователем элементы будут вьще
лены цветом (рис. 7.35).
Как видно из данного рисунка, в рассматриваемом случае выбраны две страны: Герма
ния и Россия.
244 Глава 7
. .
Англия
/ Отправить /
Изменим модуль forms.py и создадим там это поле с помощью кода листинга 7.29.
ния: None (Неизвестно), тrue (Да) или False (Нет). При этом оно никогда и ничего не про
веряет (т. е. не вызывает метод ValidationError). Если пользователь щелкнет левой кноп
кой мыши в этом поле, то ему будут предложены три варианта выбора (рис. 7.37).
Поле TimeFielct служит для ввода значений времени (например, 14:30:59 или 14°:ЗО) и по
умолчанию использует виджет Timeinput с пустым значением None. При этом вьmолняет-
Формы 247
ся проверка, является ли введенное значение либо строкой datetime . time, либо формати
рованным в определенном формате значением времени. Поле принимает один необяза
тельный аргумент input_formats.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.32.
Поле TypedchoiceField служит для выбора данных из списка. Оно аналогично полю
ChoiceField и по умолчанию также использует виджет Select с пустым значением None.
Поле имеет следующую структуру:
forms.TypedChoiceField(choises=кopтeж_кopтeжeй,
соеrсе=функция_преобразования,
empty_value=None)
���:Qцмшw!"М Крнтары
Как можно видеть, в поле одновременно вьmодится весь список, и пользователь имеет
возможность выбрать из него несколько элементов. Для этого необходимо поочередно
щелкнуть мышью на нужных элементах списка, удерживая при этом нажатой клавишу
<Ctrl>, - выбранные пользователем элементы будут выделены цветом (рис. 7.44).
В рассматриваемом случае выбраны два города: Воронеж и Томск.
250 Глава 7
Это поле предназначено для ввода универсального указателя ресурса (URL), например,
такого: http://www.google.com.
r---
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.35.
:Qm·nт• Кotaami
_J Отправить J___
Это подвал (footer) страниц сайта
Это поле агрегирует логику нескольких полей, которые вместе создают одно значение,
и имеет один обязательный аргумент - fields - кортеж полей, значения которых
очищаются и впоследствии объединяются в одно значение. Каждое значение поля очи
щается соответствующим полем в fields. Первое значение очищается первым полем,
второе - вторым полем и т. д. После очистки всех полей список чистых значений объ
единяется в одно значение по coЩ)ress().
Это поле может принимать необязательные аргументы:
□ require_all _fields - по умолчанию имеет значение тrue, в этом случае будет возни
кать ошибка проверки, если для какого-либо поля не указано значение;
□ widget - значение по умолчанию - Textinput;
□ coЩ)ress(сnисок_данных) - принимает список допустимых значений и возвращает
«сжатую» версию этих значений в виде одного значения.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.38.
Конечно, это очень упрощенный пример использования данного поля. Для того чтобы
в полной мере задействовать возможности такого комплексного поля, нужно создавать
на его основе самостоятельный класс, например:
class PhoneField(MultiValueField):
Поскольку для новичков применение поля этого типа не актуально, то в данной книге
мы не будем приводить подробности.
Поле SplitDateтimeField предназначено для ввода даты и времени в два раздельных тек
стовых поля и по умолчанию использует виджет SplitDateTimeWidget с пустым значением
None. В первое поле вводится дата, во второе поле - время. При этом делается провер
ка, является ли введенное значение либо строкой datetime .datetime, либо форматирован
ными в определенном формате значениями даты и времени.
Поле принимает два необязательных аргумента:
□ input_date_foпnats - список форматов, используемых для попытки преобразования
строки в допустимый объект datetime.date. Если аргумент input_date_foпnats не ука
зан, форматы ввода задаются по умолчанию для поля DateFielct;
□ input_time_foпnats - список форматов, используемых для попытки преобразования
строки в допустимый объект datetime . time. Если аргумент input_time_foпnats не ука
зан, форматы ввода назначаются по умолчанию для поля TimeField.
Изменим модуль forms.py и создадим там такое поле с помощью кода листинга 7.39.
Во.:�раст:
Комментарий:! 1
�----,-1-о-пт _р_а_ви_т_ь-гl
Это подвал (footer) страниц сайта
Рис. 7.51. Три текстовых поля на странице my_form.html с виджетами Textinput по умолчанию
256 Глава 7
(% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изуч?ем формы Django{% endЫock header %}
{% Ыосk content %)
<div class="container-fluid ·text-start my-2 border border-3">
<form method="POST">
{% csrf_token %}
<taЬle>
{ { form ) )
</tаЫе>
<input type="suЬmit" vаluе="Отnравить" >
</form>
</div>
{% endЬlock content %}
Во:sраст:
Комментарий:
/,
1 Отправить 1
Рис. 7.52. Три. текстовых поля на странице my_forrn.html с виджетом тextarea для поля с комментариями
Формы 257
После этих изменений при запуске нашего приложения созданные поля не будут пус
тыми (рис. 7.53).
��ОКСNМНИИ Кою:мJы
Комментарий:
1 Отправить 1
Здесь мы указали, что поле age будет отображаться на форме раньше, чем поле name,
несмотря на то, что поле name бьшо создано первым. При запуске приложения поля
будут идти в той последовательности, как указано в свойстве field_order (рис. 7.54).
1оюМtм
Отправить
Рис. 7.54. Изменение порядка следования полей на форме с использованием свойства field order
в описании класса формы
Теперь изменим порядок следования полей при определении объекта формы в пред
ставлении. Для этого внесем изменение в программный код представления views.py -
изменения выделены серым фоном (листинг 7.45).
j':i.)й'······.··.·.. · '
ЛЙСПlнr 7.45. Изме
def contact(request):
return render(request, "firstapp/contact.html")
def my_form(request):
my_form = UserForm(fielq_order=["c'!_9e", "name"])
context = {"form": my_form)
return render.(request, "firstapp/my_ form.html", context)
Здесь при описании класса формы поле name стоит на первом месте, а поле age - на
втором. Однако в представлении views.py бьш задан обратный порядок следования этих
полей с помощью свойства field_order:
userform = UserForm(field_order=["age", "name"))
В результате поля на форме будут вьmедены в такой последовательности - сначала
age, а затем name.
Во�раст:�--------'
Введите возраст
1,-о_т_n-ра-в-ит-ь'"'I
После этих изменений при запуске нашего приложения созданные поля на форме будут
представлены в трех видах (рис. 7 .56).
Имя:
Введите ФИ О
Во3раст:�------�
Введите возраст
.------;
1 Отпра ить 1
в
j Отправить 1,
Имя: Введите ФИ
О
Рис. 7.56. Текстовые поля на странице my_form.html представлены в трех разных видах
262 Глава 7
В первом случае поля формы представлены в виде таблицы, а все элементы формы вы
ровнены по левому краю. Во втором случае поля формы представлены в виде списка
и слева от идентификатора поля присутствует признак элемента списка (маркер).
В третьем случае поля формы представлены в виде параграфа (абзаца). При этом иден
тификаторы полей и сами поля выровнены по левому краю.
{% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЬlock header %}
{% Ыосk content %}
<div class="container-fluid text-start my-2 border border-3">
<h5>Валидация данных</h5>
<form method="POST">
{% csrf_token %}
<tаЫе>
{ { form.as_taЫe }}
</tаЫе>
<input type="suЬmit" vаluе="Оrправить" >
</form>
</div>
{% endЫock content %}
А в программном коде модуля forms.py сформируем четыре поля: Имя, Возраст, электронный
адрес и Согласны получать рекламу (листинг 7.51).
Если одно из полей в форме окажется незаполненным, то при нажатии на кнопку От
править пользователь получит предупреждение об ошибке (рис. 7.57).
Таким образом, чтобы отправить данные, пользователь должен будет обязательно вве
сти какое-либо значение в незаполненное поле. Однако это не всегда нужно, поскольку
одни поля всегда должны быть заполнены, а другие - нет. Предположим, что в нашем
примере пользователь не желает получать рекламу. Однако он не сможет отправить
данные до тех пор, пока не поставит флажок в поле Согласны получать рекламу
(рис. 7.58).
1 IВ
Соr11асны nо11учать реК11аму:
Отправить е-�
лжи �ь-, у_ _а_н-ов-и-т
Чтобы nродо т ст
т
ато флажок.
Для того чтобы дать пользователю возможность оставить какое-либо поле пустым, не
обходимо явно отключить для него атрибут required. В нашем случае для этого поле
reklama нужно инициировать с помощью такого программного кода:
reklama = forms.BooleanField(laЬel="Coглacны получать рекламу", required=FaJ.se)
264 Глава 7
Для полей, которые требуют ввода текста, например, CharField, EmailFielct и подобных,
иногда требуется ограничивать число вводимых символов. Это можно сделать с помо
щью параметров: max_length - максимальное число символов и min_length - минималь
ное число символов. Так, в поле, созданное с помощью кода
name = foпns.CharField(min_length=2, max_length=20)
можно будет ввести не менее двух и не более двадцати символов.
По аналогии для числовых полей IntegerField, DecimalField и FloatField можно устанав
ливать параметры: max_value и min_value, которые задают соответственно максимально и
минимально допустимые значения. Для поля DecimalField дополнительно можно задать
еще один параметр - ctecimal_places, который определяет максимальное число знаков
после запятой. Так, в поле, созданное с помощью кода
age = foпns.IntegerField(min_value=l, max_value=l20)
weight = foпns.DecimalField(min_value=З, max_value=200,
decimal_places=2)
значение возраста допускается вводить в пределах от 1 до 120 лет, а значение веса
в пределах от 3 до 200 кг. При этом число знаков после десятичной запятой может быть
не более двух.
Рассмотренные здесь атрибуты позволяют проверять введенные значения на стороне
клиента. Однако возможны варианты, когда пользователи все же смогут отправить
форму с заведомо некорректными данными, например воспользовавшись инструмента
ми для разработчиков. Чтобы предупредить такое развитие событий, можно подправить
исходный код формы, добавив к ней атрибут novalidate, который отключает в веб
браузере проверку данных на стороне клиента, и предусмотреть проверку корректности
данных на стороне сервера.
Для этого у формы вызывается метод is_valid(), который возвращает тrue, если данные
корректны, и False - если данные некорректны. Чтобы использовать этот метод, нужно
создать объект формы и передать ей данные, пришедшие из запроса.
Рассмотрим пример проверки корректности данных на стороне сервера, для чего изме
ним программный код модуля views.py (листинг 7.52, выделено серым фоном).
aef my_form(request):
if reqi.щst.щethod == ''POST":
Формы 265
if userfo;r:m.is_valid():
name = userform.cleaned_data["name"J
return HttpResponse(
"<h2►Имя введено коррректно - (О} </h2 > ". format(name) !
else:
return HttpResponse ("Qпибка вво.nа данных")
else:
userform = UserForm()
return render(request,
.___________ "f.,,.1."'r· a.a:s"tc;ca,p /my_fonn. html" { "fonn": userform} )------------
Что делает этот программный код? Если выполняется РОSТ-запрос, то вначале проис
ходит заполнение формы пришедшими данными:
userform = UserForm(request.POST)
Если данные введены корректно, то через объект cleaned_data в переменную name зано
сим введенное пользователем значение и формируем ответную страницу с сообщением,
что данные корректны:
name = userform.cleaned_data [ "name"]
return HttpResponse("<h2>Имя введено коррректно - {О) </h2 > ".format(name))
Если данные введены некорректно, то формируем ответную страницу с сообщением об
ошибке:
return HttpResponse("Qпибка ввода данных")
{% extends "firstapp/base.html" %)
{% Ыосk title %)Формы{% endЫock title %)
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %)
<div class="container-fluid text-start my-2 border border-3">
<h5>Валидация данных</h5>
<form method="POST" пovalidate>
{% csrf_token %)
<tаЫе>
{{ form.as_taЫe }}
</tаЫе>
266 Глава 7
forms.py
from django inport forms
class UserFoпn ( forms. Foпn) :
!1 = foщ.Cha:rF eld lao.e::, =-'.,_.,.1.,,,')
. ...
Итак, все готово. Теперь при запуске приложения мы получим нашу форму с одним
полем для ввода данных (рис. 7.59).
0 127.0.0.1:8000/my_form/ х +
f- ➔ С (D 127.0.0.1:8000/my_for...
Теперь заполним поле с именем клиента и нажмем кнопку Отправить. Поскольку дан
ные бьmи введены корректно, то метод userfoпn. is_valid () вернет пользователю сооб
щение о корректном вводе данных (рис. 7.61).
Формы 267
•С
1с::,!@11 �
х +
е
0 127.0.0.1:8000/my_form/ V
IF
f- ➔ С Ф 127.0.0.1:8000/my_for... <а. LВ * □
� Ааи"билеты О Янде,ос e.r Пер� G Gm.,a
�-��···=--�--
{% extends "firstapp/base.html" %}
{% Ыосk title %)Формы{% endЫock title %}
Формы 269
} )</div>
field.errors)}</div>
</div>
{% endЬlock content %)
В этом шаблоне форма представляет собой набор полей, расположенных внутри цикла
for. Спомощью выражения { % for field in form % ) в цикле делается проход по всем по
лям формы, при этом есть возможность управлять отображением, как самих полей, так
и связанных с ними атрибутов: ошибок, текста подсказки, меток и т. д.
Здесь мы сгруппировали отображение следующих значений для каждого поля формы:
□ field. laЬel_tag - элемент label, который показывает метку поля;
□ field - само поле для ввода данных;
□ field. errors - ошибки валидации,
связанные с полем.
□ Теперь в форме будет отображаться следующая информация: метка поля, под ней
само поле. Если в поле пользователь введет ошибочные данные, то информация об
ошибке будет отображена под соответсвующим полем.
Если мы теперь запустим наше приложение, то получим следующий вид формы
(рис. 7.62).
�� окомпании КонIМW
Изучаем формы Django
- -
Валидацияrруnпыполей
Имя клиен.а:
Возраст клиента:
Если мы теперь при незаполненных полях нажмем кнопку Отправить, то возле каждо
го поля получим сообщение о наличии ошибки (рис. 7.63).
Как видно из рис. 7.63, сообщение о наличии ошибки появилось рядом только с неза
полненным полем.
• Обязательное поле.
1 Отправить [
Поле ввода может содержать несколько ошибок. В этом случае можно с помощью тега
for последовательно вьmести все возможные ошибки:
{% for error in field.errors %}
<div class="alert alert-danger">{{error}}</div>
{% endfor %}
{% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЬlock title %}
{% Ыосk header %}Изучаем формы Django{% endЬlock header %}
{% Ыосk content %}
<
</st
<div iner-fiuid text-start my-2
{% endfor %}
</div>
<input type="suЬmit" vаluе="Отnравить" >
</form>
</div>
{% endЬlock content %}
Здесь в заголовке head задан стиль alert{color:rect} (красный цвет для отображения оши
бок) и стили вьmода полей, которые объединены в группы:
□ margin:20px- отступы;
□ wictth:250px-шиpинa рамок полей;
□ height:25рх- высота рамок полей;
□ border-radius:l0px- радиус округления углов рамок полей.
Далее задан стиль контейнера Bootstrap:
□ text-start- прижимать текст в контейнере к левому краю;
□ my-2- вертикальные отступы между элементами контейнера 2 пункта;
□ border border-5- ширина рамки контейнера 5 пунктов;
□. border-warning- цвет рамки контейнера (warning).
В блоке с полями формы задан индивидульный стиль для вывода подсказок шрифтом
синего цвета (style="color:Ыue"). Наконец, ошибки выдаются в теге с циклом {% for
error in field. errors %} с использованием специального класса Bootstrap- class="alert
alert-danger".
272 Глава 7
Если после этих изменений запустить наше приложение, то вся форма будет выглядеть
так, как показано на рис. 7.64.
На данном рисунке видно, что рамки имеют округлую форму, а подсказки выдаются
синим цветом.
0 Формы х + V
� ➔ С ф 127.0.0.1:8000/my_for... €\. te * □ �
�, А5иабметъ� О Яндекс lt Перевести G Gmait
Не менее 3-хсимволов
Возраст клиента:
От 1 до 120 лет
1 Отправить 1
Отправить
После этого в шаблоне формы firstapp\my_form.html нужно подключить классы field и error
и задать им желаемые свойства, как показано в листинге 7.61 (изменения вьщелены
серым фоном).
{% extends "firstapp/base.html" %)
{% Ыосk title %)Формы{% endЫock title %)
{% Ыосk header %)Изучаем формы Django{% endЫock header %)
{% Ыосk content %)
<style>
.field(font-weight:bold; color:darkЫue)
.error{color:red)
</style>
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Стилиэация группы nолей</h5>
<form method="POST" novalidate>
{% csrf_token %)
<div class="form-group my-2">
{% for field in form ,% }
<ф.v>{{field.laЬ�tag) }</div>
<div>{{field) L<Wlx:;:
�d:i.v class="error';>{(field.errors JlSJ<liv>
{% endfor %)
</div>
<input type="suЬmit" vаluе="Отnравить" >
</form>
</div>
{% endЫock content %)
274 Глава 7
В этом программном код� для меток полей задан полужирный шрифт (font-weight:bold)
темно-синего цвета (color:darkЬlue). Для сообщений об ошибках задан красный цвет
шрифта - error{color: red J.
Если после этих изменений запустить наше приложение, то будет видно, что метки по
лей вьmодятся полужирным шрифтом темно-синего цвета, а сообщения об ошибках
выводятся красным цветом (рис. 7.66).
1 1
• Обязательное поле,...,.;;_,_
Сообw,l!ние
об ошибке
Отправить
В этом коде через параметр виджетов attrs задаются атрибуты того НТМL-элемента,
который будет генерироваться. В частности, здесь для обоих полей устанавливается
атрибут class, который представляет класс myfield.
Теперь нужно в шаблоне главной страницы firstapp\my_form.html определить класс myfield
и задать для него набор свойств, как показано в листинге 7.63 (вьщелено серым фоном).
{% extends "firstapp/base.html" %)
{% Ыосk title %)Формы{% endЫock title %)
{% Ыосk header %)Изучаем формы Django{% endЫock header %)
{% Ыосk content %)
Формы 275
</style>
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Стилизация группы полей</h5>
<form method="POST" novalidate>
{% csrf_token %}
<div class="form-group my-2">
{% for field in form %}
<div>{{field.label_tag}}</div>
<div>{{field}}</div>
<div class="error">{{field.errors}}</div>
{% endfor %}
</div>
<input type="suЬmit" vаluе="Отправить" >
</foпn>
</div>
{% endЫock content %}
Если после этих изменений запустить наше приложение, то форма будет вьmедена
в следующем виде (рис. 7.67).
Возраст клиента:
(63
1 Отправить 1
{% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %}
<div class="container-fluid text-start my-2
border border-5 border-warning">
<hS>Стилизация группы полей</hS>
<form method="POST">
{% csrf_token %}
<div class="form-group·my-2">
{% for field in form %}
<div>{{field.laЬel_tag}}</div>
<div>{{field}}</div>
<div class="error">{{field. errors}}</diy>
{% eпdfor %}
</div>
<input type="suЬmit" vаluе="Отправить" >
</form>
</div>
{% endЫock content %}
Для создания формы здесь использован стандартный элемент НТМL <form>. В начале
формы помещен встроенный тег Django {% csrf_token %}, который позволяет защитить
приложение от CSRF-aтaк, добавляя в форму сsrf-токен в виде скрытого поля. В ниж
ней части формы помещена кнопка для отправки содержимого этой формы на сервер.
ПОЯСНЕНИЕ
CSRF (Cross-Site Request Forgery, также XSRF) - опаснейшая атака, которая приводит
к тому, что хакер может выполнить на неподготовленном сайте массу различных действий
от имени других зарегистрированных посетителей.
def aЬout(request}:
return render(request, "firstapp/aЬout.html"}
def contact(request}:
return render(request, "firstapp/contact .html"}
def my_foпn(request}:
if request.method = "POST":
userfoпn = UserFoпn(request.POST)
if userfoпn.is_valid(}:
name = request.POST .get("name';} # полу"!Ить значение поля Имя
age = request.POST.get("age"} # получить значение поля Возраст
output = "<h2>Пользователь</h2><h3>Имя - {О},"
"Возраст - {l} </hЗ >".format(name, age}
return HttpResponse(output}
userfoпn = UserFoпn(}
return render(request, "firstapp/my_foпn.html", { "foпn": userfoпn))
1Климоs Иrорь
Возраст клиен та:
1 Отnраsить 1
Это nодвал (footer) стр аниц сайта
Рис. 7.68. Ввод данных в форму при первой загрузке страницы index.html
Если теперь нажать на кнопку Отправить, то запрос будет иметь тип POST
(request.method = "POST"), это значит, что данные отправляются на сервер. В этом случае
отправляемые из формы данные присваиваются переменным name и age, а их значе
ния - переменной output. После этого значения из output отправляются на сервер через
объект HttpResponse. На сервере эти данные могут быть либо записаны в Бд, либо обра
ботаны одной из процедур, которая выполнит определенные действия. Поскольку мы
еще не изучали возможности работы Django с Бд, в этом примере ответ отправляется
пользователю на ту же НТМL-страницу (рис.7.69).
278 Глава 7
х +
� ➔ С ф 127.0.0.1:8000/my_for... 0_ � * □ е,
':'( Авиабилеты О Яндекс -. Перевесrи G Gmaif
Пользователь
И.i\lJI - Климов Игорь, Возраст - 63
7. 7. Краткие итоги
В этой главе бьmи приведены сведения о формах. Мы узнали, как создать форму, как
определить, настроить и стилизовать в форме поля, как проверить корректность вве
денных в форму данных. Теперь нам нужно разобраться с тем, как Django работает
с самими данными. Понять, как можно сохранить в БД данные, которые пользователь
ввел в форме, или как получить из БД данные, запрошенные пользователем через свой
веб-браузер. В Django все действия с информацией, которая хранится в БД, осуществ
ляются через так называемые модели данных, или, просто, модели. Изучению моделей
данных посвящена следующая глава. В ней рассматриваются методы работы с данными
через модели, не прибегая к SQL-запросам - традиционному способу взаимодействия
с СУБД.
ГЛАВА 8
Практически любое веб-приложение, так или иначе, работает с базой данных. При этом
с системой управления базами данных (СУБД) приложение общается каким-нибудь
универсальным способом, например посредством языка SQL. Однако программисту
чаще всего хочется иметь некую абстракцию, позволяющую большую часть времени
работать с привычными сущностями языка. Такой абстракцией является Object-Rela
tional Mapping (ОRМ) - отображение сущностей предметной области и их взаимосвя
зей в объектах, удобных для использования программистом.
Имеются разные подходы к тому, как нужно изолировать пользователя от конкретного
хранилища данных. Есть такие, которые полностью скрьmают всю работу с БД, - вы
пользуетесь объектами, изменяете их состояние, а ОRМ неявно синхронизирует со
стояние объектов и сущностей в хранилище. Другие ОRМ всего лишь оборачивают
сущности БД в структуры языка, но все запросы нужно писать вручную. Это два раз
ных полюса, каждый со своими плюсами и минусами. Авторы Django решили остаться
где-то посередине.
В Django вы работаете с объектами и выполняете вручную их загрузку и сохранение,
однако используете для этого привычные средства языка - вызовы методов и свойств.
При этом Django берет на себя обеспечение правильной работы вашего приложения
с конкретными хранилищами данных. Эта изоляция от конкретного хранилища позво
ляет применять разные БД в различных условиях: при разработке и тестировании
задействовать легковесные СУБД, а при развертывании сайтов в реальных условиях
переходить на более мощные и производительные базы данных.
Термин «модель» часто употребляется в качестве замены словосочетания «Django
ОRМ», поэтому мы будем им пользоваться и в рамках этой книги. «Модель» говорит
нам о том, что наша предметная область смоделирована с помощью средств фреймвор
ка. При этом отдельные сущности тоже называются моделями - модели поменьше со
бираются в большую «Модель» всей предметной области.
Связь между моделями и таблицами в БД максимально прямая: одна таблица - одна
модель. В этом плане Django ОRМ не отходит далеко от схемы БД - вы всегда имеете
представление о том, как фактически описаны ваши данные с точки зрения СУБД. Что
очень полезно, когда нужно что-либо где-то оптимизировать!
280 Глава В
При создании приложения по умолчанию в его каталог добавляется файл models.py, ко
торый применяется для определения и описания моделей. Модель представляет собой
класс, унаследованный от django. dЬ.models.Model.
Модели данных Django 281
Т erminaf: Local +
С: \Use,-s\Anatoly\PycharmProjects\iJeb_1 \hello>python manage.py makemigrations
Migrations for 'firstapp':
firstapp\migrations\OO!Н_initial.py
- Create model Person
�
� C:\Users\Anatoly\PycharmProjects\Web_l\hello>
Как можно видеть, после выполнения этой команды создан файл с миграцией
firstapp\migrations\0001_initial.py и получено сообщение: Create model Person (создана модель
Person).
Рис. 8.3. Окно PyCharm: описание полей модели данных в файле миграции 0001_initial.py
operations = [
migrations.CreateModel(
name=' Person',
fields= [
('id', models.AutoField(auto_created=True,
primary_key=True, serialize=False,
verbose_name=' ID')),
('name', models.CharField (max_length=20)),
('age', models. IntegerField()),
],
),
Это и есть результаты первого шага миграции. Здесь можно заметить, что в процессе
миграции создано не два поля, как было описано в модели, а три - появилось допол
нительное поле id, которое будет представлять первичный ключ в таблице базы дан
ных. Такое поле добавляется автоматически по умолчанию. Поэтому в·Django в самой
модели не требуется для таблиц базы данных явным образом определять ключевые
поля - они будут создаваться автоматически. На первом шаге бьmо создано только
описание полей для таблицы Person, в которой будут храниться данные о клиентах, при
этом сама таблица в БД еще отсутствует.
На втором шаге миграции необходимо на основе описания полей в модели данных соз
дать соответствующую таблицу в БД. Это делается с помощью команды
python manage.py migrate
Рис. 8.4. Окно терминала PyCharm: создание таблиц в БД при миграции модели данных
� SQliteStudи, (3.2J.}
·!Jataba,� Structure V1ew Т oois Hel;:,
Таблицы (Щ
� auth_group
i±J·· !rn auth_group_permissions
:±1 · [jj auth_permission
Рис. 8.5. Окно приложения SQLiteStudio:
;Б · iE] auth_user таблица firstapp__person,
i±J · � auth_user_groups
созданная в БД при миграции
!±J·· in auth_user_user_permissions модели данных
!il irn django_admin_log
[t-1· � django_content_type
l±J · Е django_migrations
:Б · [е django_session
В IJ\firstapp_person
В. llli1!] Столбць, (3}
iш) id
iПEiname
[![] age
,ф Индексы
(J Триггеры
формируются автоматически, при этом имя таблицы состоит из двух частей: из имени
приложения и имени модели. В нашем случае таблица будет иметь имя firstapp__person.
Методы all(), filter() и exclude() возвращают объект Queryset. Это, по сути, некое про
межуточное хранилище, в котором содержится информация, полученная из БД. Объект
QuerySet может быть создан, отфильтрован и затем использован фактически без вьmол
нения запросов к базе данных. База данных не будет затронута, пока вы не инициируете
новое выполнение Queryset. Рассмотрим последовательно все указанные методы.
Метод get()
Метод get() возвращает один объект, т. е. одну запись из БД по определенному усло
вию, которое передается в качестве параметра. Пусть, например, в программе имеется
следующий код:
klientl = Person.objects.get(name="Bиктop")
klient2 = Person.objects.get(age=25)
klientЗ = Person.objects.get(name="Bacилий", age=23)
В этом случае в переменную klientl будет считан объект, у которого поле nаmе="Виктор",
в переменную klient2 - объект, у которого поле age=25. Соответственно в переменную
klientЗ будет считан объект, у которого поле nаmе = "Василий" и поле аgе=2З.
При использовании этого метода нужно учитывать, что он предназначен для выборки
таких объектов, которые имеются в базе данных в единственном числе. Если в таблице
не окажется подобного объекта, то будет выдана ошибка uмя_мoдeлu.DoesNotExist.
Если же в таблице присутствует несколько объектов, которые соответствуют указанно
му условию, то будет сгенерировано исключение мultipleObjectsReturned. Поэтому сле
дует применять этот метод с достаточной осторожностью.
Метод get_or_create()
Метод get_or_create() получает объект из Бд, а если его там нет, то он будет добавлен
в БД как новый объект. Рассмотрим следующий код:
ЬоЬ, created = Person.objects.get_or_create(name="Bob", age=24)
print(bob .name)
print(bob.age)
Модели данных Django 289
Этот код вернет добавленный в БД объект (в нашем случае- переменную ьоь) и буле
во значение (createct), которое будет иметь значение тrue, если добавление прошло
успешно.
Метод а/1()
Метод all() позволяет получить все имеющиеся объекты из базы данных, например:
people = Person.objects.all()
Метод count(J
Метод count() позволяет получить число объектов в таблице базы данных, например:
people = Person.objects.count()
Метод filter()
Если требуется получить объекты, которые соответствуют определенному критерию,
то применяется метод filter(), который в качестве параметра принимает критерий вы
борки. Например:
people = Person.objects.filter(age=23)
people2 = Person.objects.filter(name="Tom", age=23)
Здесь в people будут помещены все объекты из БД, для которых age=23, а в people2 - все
объекты с параметрами name="Tom" и age=23.
Метод exclude()
Метод exclude() позволяет выбрать из БД все записи, за исключением тех, которые
соответствуют критерию, переданному в качестве параметра:
people = Person.objects.exclude(age=23)
Здесь в people будут помещены все объекты из БД, за исключением тех, у которых
age=23.
Можно комбинировать методы exclude() и filter():
people = Person.objects.filter(name="Tom") .exclude(age=23)
Здесь в people будут помещены все объекты из БД с именем name="Tom", за исключением
тех, у которых age=23.
Метод in_bu/k()
Метод in_bulk() является наиболее эффективным способом для чтения большого коли
чества записей. Он возвращает словарь, т. е. объект ctict, тогда как методы all(),
filter() и exclude() возвращают объект ·ouerySet.
Все объекты из БД можно получить с помощью следующего кода:
people = Person.objects.in_bulk()
Для получения доступа к одной из выбранных из БД записей нужно указать идентифи
катор записи в словаре:
290 Глава В
for id in people:
print(people[id] .narne)
print(people[id] .age)
С помощью метода in_bulk() можно получить и часть объектов из БД. Например, в сле
дующем программном коде из БД будут получены только те объекты, у которых клю
чевые значения полей равны 1 и 3:
people2 = Person.objects.in_bulk([l,3])
for id in people2:
print(people2[id] .narne)
print(people2 [id] .age)
Здесь метод in_bulk возвращает словарь, где ключи представляют ict объектов, а значе
ния по этим ключам - собственно эти объекты, т. е. в нашем случае объекты Person.
Здесь полю age присваивается уже имеющееся значение, увеличенное на единицу. При
этом важно учитывать, что метод update обновляет все записи в таблице, которые соот
ветствуют условию (в приведенном примере таким условием является id=2).
Когда необходимо обновить все записи в столбце таблицы БД вне зависимости от усло
вия, то нужно комбинировать метод update() с методом all() без параметров:
from django.dЬ.models import F
Person.objects.all() .update(name="Миxaил")
Person.objects.all() .update(age = F("age") + 1)
Здесь всем клиентам будет присвоено значение Михаил, а возраст всех клиентов будет
увеличен на единицу.
Для обновления записей в БД есть еще один метод - update_or_create. Если запись
существует, то этот метод ее обновит, а если записи нет, то добавит ее в таблицу:
values_for_update= {"name":"Миxaил", "age": 31)
ЬоЬ, created = Person.objects.update_or_create(id=2,
defaults = values_for_update)
Здесь в первой строке в элемент person загружена информация из строки таблицы базы
данных с ict=2, а во второй строке вызван метод, который удалил из таблицы БД эту
строку.
Если не требуется получение отдельного объекта из базы данных, тогда можно удалить
объект одной строкой программного кода с помощью комбинации методов filter() и
delete():
Person.objects.filter(id=4) .delete()
Эта команда удалит строку с ict=4 непосредственно в базе данных, без предварительной
загрузки ее содержимого в приложение.
Страница HTML
(шаблон Django)
форма, которая содержит тот же набор полей. Когда форма через представление (view)
отображается на НТМL-странице, пользователь опять видит тот же набор полей, по
скольку форма в виде объекта передается в шаблон Django. После того, как пользова
тель ввел данные в эти поля и отправил их на сервер, они записываются в ту таблицу
БД, которая определена в модели. В итоге пользователь видит на НТМL-странице об
новленные данные, которые пришли из БД через представление в ту же форму (или
в другую форму).
Поля формы сами по себе являются объектами классов, которые управляют данными
формы и проверяют их при отправке в БД. Поля имеют разные типы: дата (oateFielct),
файлы (FileFielct), изображения (rmageFielct) и т. п. Зная тип поля из модели, Django са
мостоятельно определяет, какие проверки необходимо выполнить, какие SQL-запросы
потребуются и как отобразить поле пользователю.
Поле формы представляется пользователю в браузере через шаблоны Django как «вид
жет» НТМL. Каждый тип поля имеет соответствующий класс виджета по умолчанию,
но при необходимости их можно переопределить.
При рендеринге (визуализации) объекта в Django обычно вьmолняются следующие шаги:
□ формирование данных в представлении (например, получение из БД);
□ передача данных в контекст шаблона;
□ расширение шаблона с использованием разметки НТМL и показа данных в шаблоне.
Визуализация формы в шаблоне включает почти те же шаги, что и визуализация любо
го другого объекта, но есть некоторые ключевые отличия.
В случае экземпляра модели, которая не содержит данных, нет необходимости что
либо делать с ней в шаблоне. С другой стороны, имеет смысл визуализировать неза
полненную форму. Это нужно, когда пользователь должен ввести какие-либо данные.
С другой стороны, в форме необходимо показать те данные, которые он уже передал
в БД. Поэтому, когда создается форма, она может остаться пустой или предварительно
заполненной данными из различных источников, например:
□ данными, введенными ранее пользователем в этой форме;
□ данными, полученными из других моделей и форм;
□ данными, введенными пользователем в БД в текущем сеансе работы с формой.
Последний из этих вариантов наиболее интересен, потому что в этом случае пользова
тель может не только вводить данные в БД через форму, но и тут же контролировать
как корректность введенных данных, так и то, что данные действительно были записа
ны в БД.
Здесь был выполнен импорт пакета Django forms, который отвечает за работу с форма
ми. Затем создана пользовательская форма в виде класса с именем NameForm на основе
базового класса (forms.Form). После этого созданы поля (объекты), которые будут ото
бражены в форме (field_l, field_2, ...) . Все эти поля будут отображены в форме в том
порядке, в каком они бьши созданы.
Создание класса формы NameForm при помощи описанного примера, является довольно
гибким способом, позволяющим создавать формы произвольной структуры и в связке
с любой моделью или моделями.
Однако если вам нужна форма для отображения полей из одной модели, то можно по
ступить проще. Ведь в самой модели уже содержится большая часть информации, ко
торая необходима для построения формы: сами поля, текстовые метки полей, содержа
ние полей по умолчанию и т. п. Для того чтобы не дублировать информацию в форме,
которая уже есть в модели, проще воспользоваться классом ModelForm, который помогает
создавать формы непосредственно из модели. Класс мodelForm может применяться в ва
ших представлениях (view) точно так же, как и "классический" класс формы Form.
Базовая реализация мodelForm будет содержать те же поля, что и класс формы Form. Все
что необходимо сделать, - внутри вашего нового класса добавить класс меtа и связать
его с моделью model, а затем перечислить поля модели, которые должны быть включены
в форму, в переменной (объекте) fields. Можно включить все поля при помощи инст
рукции fields = '_all_' или можно воспользоваться атрибутом exclude (вместо fields),
чтобы определить поля модели, которые нужно исключить. Программный код создания
модели на основе класса ModelForm будет иметь следующую структуру:
from django iпport forms
from .models iпport <name_model>
class NameForm ( forms.ModelForm) :
class Meta:
model = <name model>
fields = ' all '
# fields = [' field_l', ' field_l']
Здесь сначала был импортирован пакет Django forms, который отвечает за работу
с формами. Кроме того, выполнен импорт модели с именем <name_model>, которая была
создана ранее. Затем вьmолнена инициализация пользовательской формы в виде класса
с именем NameForm на основе базового класса ( forms.ModelForm) . После этого создан объект
model (можно задавать любое имя) на основе импортированной модели. И в заключение
создается объект fields, который включает все поля из импортированной модели.
Можно, конечно, задать имена полей и вручную, как это сделано в закомментирован
ной строке, однако это не рекомендуется, т. к. опять происходит дублирование кода.
Явно задавать поля рекомендуется в тех случаях, когда в форме пользователь должен
внести данные только в часть полей модели.
Если представление получает запрос GET, то будет создан пустой экземпляр формы
(form), который через параметр context будет передан в шаблон 'name.html' для отобра
жения. Этого мы можем ожидать при первом посещении формы через ее URL-aдpec.
Если форма отправляется через запрос POST (пользователь ввел данные), представле
ние снова создаст экземпляр формы и заполнит его данными из запроса: это называется
«привязкой данных к форме» (теперь это связанная форма):
form = NameForm(request.POST)
После этого вызывается метод формы is_valid() . Если в заполненных данных есть
ошибки (form.is_valid()=False), то происходит возврат к шаблону с формой. На этот раз
форма не пустая, она будет заполнена данными, отправленными пользователем. Теперь
эти данные можно исправлять и снова отправить на сайт.
Если form.is_valid()=Тrue (в данных нет явных ошибок), мы можем получить все прове
ренные данные формы в атрибуте cleaned_ctata и вьmолнить с ними любые действия.
А можем сохранить все введенные данные в БД простой инструкцией - form.save() .
После этого в инструкции return мы указьmаем, на какую страницу сайта идти дальше.
Terminal: Locaf +
System check identified some issues:
firstapp'.migrations\!3002_company_alter_persoп_managers_product.py
(reate шodel Company
Change manageгs on person
Create model Pгoduct
operations = [
migrations.CreateModel(
name='Cornpany',
fields= [
('id', models.BigAutoField(auto _created=Тrue, primary_key=Тrue,
serialize=False, verbose_name='ID')),
( 'name', models.CharField(max_length=З0)),
],
) '
migrations.AlterModelManagers(
name='person',
managers= [
('object_person', django.dЬ.models.manager.Manager()),
],
),
migrations.CreateModel(
name='Product.',
fields= [
('id', models.BigAutoField(auto_created=Тrue, primary_key=Тrue,
serialize=False, verbose_name='ID')),
('name', models.CharField(max_length=З0)),
('price', models. IntegerField()),
('cornpany', moels.ForeignKey
(on_delete=django.dЬ.models.deletion.CASCADE,
to='firstapp.cornpany')),
],
),
Разберемся, какие действия прописаны в этом файле. Во-первых, его номер 0002 гово
рит о том, что это уже вторая миграция. Во-вторых, что эта миграция является зависи
мой от файла с первичной миграцией:
dependencies = [('firstapp', '000l_initial'),]
Модели данных Django 299
□ модели таблицы данных о продукции компании - с именем пате= ' Product' и че-
тырьмя полями: 'id', 'name', 'price' И 'company '.
При этом указано, что в таблице со сведениями о продуктах компании поле company
является связующим с главной таблицей, и предусмотрено каскадное удаление всех
записей для случая, если компания будет удалена из главной таблицы.
Теперь внесем эти изменения в саму базу данных, для чего в окне терминала PyCharm
(рис. 8.8) вьшолним команду:
python manage.py migrate
Тerminэl: local +
С: \U$ers \Алаtо 1 y\Pycharn.Project$ \щ:Ь_! \lн: l lo >python rnanage. ру migr.ite
Operations to perform,
Apply all migrations: admin, auth, ccntenttypes, fiгstapp, sessions
Running migratioлs:
Applying fiгstapp.0002_compaлy_pгoduct ... ОК
C:\Users\Aлatoly\Pychar,..Projects\.Jeb_l\hello►
Рис. 8.8. Создание таблиц в БД на основе миграции моделей данных Company и Product
В результате миграции на основе моделей Company и Product в базе данных SQLite авто
матически будут созданы таблицы: firstapp_company и firstapp_product (рис. 8.9).
Как видно из данного рисунка, в сформированных таблицах автоматически созданы
ключевые поля для идентификации записей (ict), а также в таблице firstapp_product по
явилось поле company _id для связи этой дочерней таблицы с родительской таблицей
company. Именно через это поле в программном коде можно будет получать связанные
данные. Например, если требуется получить идентификатор компании, которая произ
водит этот продукт, нужно воспользоваться командой:
id_company = Product.objects.get(id= l) .company .id
Если требуется получить название компании, которая производит этот продукт, нужно
воспользоваться командой:
name_company = Product.objects.get(id= l) .company .name
Базы данных
Табличный в1о1д
Фильтр по имени
dЬ (SQlJteЗ)
,. dbO (SQlit• З}
,. id name price companyjd
Таблищ,1 (В)
!> [!jJ auth_group
!> � auth_group_permissions
!> lr!J auth_permission
t> ['] auth_user
1> IE1J auth_user_groups
!> ['] auth_user_user_permi ..
!> frn1] django_admin_log
1> О django_content_type
!> О django_migrations H05bte
!> � django_session
таблицы 5 БД
1> � firstapp_company
!> � firstapp_person
" firstapp_pr=odu=ct-=--=---'I Поле для
,. Столбщ,1 (4)
связы5ания
lm].id
таблиц
[miJ name
1m] price
[m company_id
Рис. 8.9. Таблицы, созданные в БД на основе миграции моделей данных Соп-раnу и Product
С точки зрения модели Соп-раnу (родительская таблица в БД) она не имеет никаких
свойств, которые связьmали бы ее с моделью Product (дочерняя таблица в БД). Но с по
мощью команды, имеющей следующий синтаксис:
"главная_модель" . "зависимая_модель"_set
Листинг 8.3. Пример кода выполнения операций в зависимой модели из главной модели
подавателей. Еще один пример - это книги и авторы к_ниг. У одной книги может быть
несколько авторов, в то же время у одного автора может быть несколько книг.
Связь «многие ко многим» создается с помощью трех таблиц: две их них (А и В) -
«источники» и одна таблица - соеди·нительная. Первичный ключ соединительной таб
лицы (А-В) - составной. Он состоит из двух полей: двух внешних ключей, которые
ссылаются на первичные ключи таблиц А и В. Все первичные ключи должны быть уни
кальными. Это подразумевает, что комбинация полей А и В должна быть уникальной
в таблице А-В.
Еще один пример такой связи - номера гостиницы и ее гости. Между таблицами «Гос
тю> и «Комнаты» (или номера) существует связь «многие ко многим»: одну комнату
могут заказать многие гости в течение определенного времени, и в течение этого же
промежутка времени гость может заказать в гостинице разные комнаты. Однако соеди
нительная таблица в таком случае может не являться классической, состоящей только
из двух внешних ключей. Она может быть отдельной сущностью с дополнительными
полями, имеющей связи с двумя другими сущностями (при этом уникальность ключей
должна соблюдаться).
Вследствие природы отношения «многие ко многим» совершенно неважно, какая из
таблиц родительская, а какая - дочерняя, потому что по своей сути такой тип отноше
ний является симметричным.
Для представления отношения «многие ко многим» Django самостоятельно создает
промежуточную связывающую таблицу. По умолчанию имя этой таблицы образуется
из имен двух соединяемых таблиц.
Рассмотрим, как можно связать две таблицы в БД через связанные модели на примере:
«много учебных курсов - много студентов». Для создания отношения «многие
ко многим» применяется тип связи мanyТoManyField. Итак, добавим в файл hello/firstapp
/models.py код листинга 8.4.
В этом примере модель course представляет собой учебные курсы, а модель student -
студентов. Здесь нет родительской и дочерней таблицы, они равнозначны.
Новая сущность courses, устанавливающая отношение «многие ко многим», создается
с помощью конструктора models.мanyТoManyField. В результате генерируется промежу
точная таблица, через которую, собственно, и будет осуществляться связь.
Теперь запустим в окне терминала PyCharm (рис. 8.1 О) миграцию, подав команду
python manage.py makemigrations
Тerminal: local · +
C:\Users\Anatoly\PycharmProjects\lveb_l\hello>python manage.py makernigrations
Migrations for 'firstapp':
firstapp\migrations\0003_course_student.py
Create ll!Odel Course
- Create model Student
operations = [
migrations.CreateModel(
name='Course',
fields= [('id', models.AutoField(auto_created=Тrue,
primary_key=Тrue, serialize=False,
verbose_name='ID')),
('name', models.CharField(max_length=ЗO)),
],
),
migrations.CreateModel(
name='Student',
fields= [('id', models.AutoField(auto_created=True,
primary_key=Тrue, serialize=False,
verbose_name='ID')),
('name', models.CharField(max_length=ЗO)),
('courses',
models.ManyТoManyField
(to='firstapp.Course')),
],
),
И 'name'.
При этом указано, что между таблицами имеется связующая таблица, которая обеспе
чивает связь «мноmе ко многим», и к этим связям можно обращаться через свойство
courses.
Теперь внесем эти изменения в саму базу данных, для чего в окне терминала PyCharm
(рис. 8.11) вьшолним команду python manage.py migrate.
В результате миграции на основе моделей course и student в базе данных SQLite автома
тически будут созданы уже не две, а три таблицы: firstapp_course, firstapp_student и
firstapp_course_student (рис. 8.12).
В нашем случае таблица с именем firstapp_student_courses выступает в качестве свя
зующей таблицы. Ей автоматически присвоено имя по шаблону:
имя приложеIМЯ+имя_таQЛИЦЫ+имя_ связующ:!ГО_поля_из_ таfurицы
304 Глава В
Рис. 8.11. Создание таблиц в БД на основе миграции моделей данных Course и Student
г! Базы данных
Ф11льтр по имени
1> IIJ db CSQtite »
4 dbO {5,Qlite З}
4 ТабЛИLIРI (16)
1> auth_group
[> auth_group__permissions
t, auth __permission Поля се,язующей
1> auth_user таблицы
1> auth_user_groups
t> auth_user_user_permissions
[> django_adminJog
� django_coпtent_type
t> django_migrations
t> django_session
Новые
t> firstapp_company
таблицы вБД
1> firstapp_course
t> firstapp__persoп
t> firstapp__product
[>
А в самой связующей таблице имеются всего два поля с ключами из двух связанных
таблиц: student_id и course_id.
Через свойство courses в модели stuctent мы можем получать курсы, связанные со сту
дентом, и управлять ими. Рассмотрим следующий код:
# создадим студента с именем Виктор
stud_viktor = Student.objects.create(name="Bиктop")
# создадим один курс И добавим В него Виктора
stud_viktor.courses.create(name="Maтeмaтикa")
# получим все курсы студента Виктора
all_courses = Student.objects.get(name="Bиктop") .courses.all()
# получаем всех студентов, которые посещают курс Математика
all_student = Student.objects.filter(courses_name="Maтeмaтикa")
Стоит обратить внимание на последнюю строку кода, где выполняется выборка студен
тов по посещаемому курсу. Для передачи в метод filter() имени курса задан параметр
Модели данных Django 305
Следует учитывать, что не всегда такая организация связи «многие ко многим» может
подойти. Например, в нашем случае создается промежуточная таблица, которая хранит
только id студента и id курса. Если нам нужно в промежуточной таблице хранить еще
какие-либо данные, например дату зачисления студента на курс, его оценки и т. д., то
такая конфигурация не подойдет. И тогда правильнее будет создать промежуточную
сущность вручную (например, запрос или хранимую процедуру), которая связана от
ношением «один ко многим» с обеими моделями.
Здесь мы создали модель пользователя (user) с одним полем name и модель учетных
данных пользователя (Account) с двумя полями: login и password. Для создания отноше
ния «один к одному» был применен конструктор типа models.oneтoOneField(). Его пер
вый параметр указьшает, с какой моделью будет ассоциирована эта сущность (в нашем
случае ассоциация с моделью user). Второй его параметр (on_delete=пюdels.CASCADE) гово
рит, что данные текущей модели (Account) будут удаляться при удалении связанного
объекта главной модели (user). Третий параметр (primary_key=Тrue) указьmает, что внеш
ний ключ (через который идет связь с главной моделью) одновременно будет высту
пать и в роли первичного ключа и соответственно создавать отдельное поле для пер
вичного ключа.
Теперь внесем эти изменения в саму базу данных, для чего вьmолним в окне терминала
PyCharm последовательно две команды:
python manage.py makemigrations
python manage.py migrate
В результате миграции в базе данных SQLite будут созданы следующие таблицы: таб
лица firstapp_user с полями id и name и таблица fir·stapp_account с полями login, password
и user_id (рис. 8.13).
Как можно видеть, в таблице firstapp_account нет собственного первичного ключа
(id) - его роль вьmолняет ключ user_id, который одновременно служит для связи
с таблицей firstapp_user.
С помощью свойства users в модели Account мы можем манипулировать связанным
объектом модели user:
# создадим nользователя Александр
alex = User.objects.create(name="Aлeкcaндp")
# создадим аккаунт nользователя Александр
асс = Account.objects.create(login = "1234",
password="6565", user= alex)
Модели данных Django 307
[Фильтр по имени
1> • dJ (SQl.ite 3)
• сЬ0 {SQut•3}
■lв ... 11 а ml11 а
• g} Тамu,, аЗ> login password
1> • ill..lth_goцp
1> • ill..lth_goцp_permissions
1> 1!] ill..lth_permission
1> [mJ ill..lth_user
m
1> 1!] auth_user_goups
1> i1Uln_user_userJ)t:111issio11s
m
fiiiil
t> Ш d" . _admin_.,,,
JilП!IO •-
t> django_conll!nt_type
l> [ml django_migations
1> im django_session
1> .• r..шw"llCCDUnt ··-
!) 1!] lirst,pp_coщ,any
t> llm] lirst,pp_axrse
t> lm] lirst,pp_person
[11 lirst,pp_product
m
1>
m
!) lirst,pp-'student
!> lirst,pp_student
1> [ml lirst,pp_user
Рис. 8.13. Таблицы, созданные в БД на основе миграции моделей данных
со связью «один к одному» на основе моделей User и Account
При этом через модель user мы также можем влиять на связанный объект Account. Не
смотря на то что явным образом в модели user определено только одно свойство -
narne, при связи «один к одному» неявно создается еще одно свойство, которое назьmа
ется по имени зависимой модели и указьmает на связанный объект этой модели. В на
шем случае это свойство будет назьmаться account:
# создадим пользователя Александр
alex = User.objects.create(nаmе="Александр")
# создадим аккаунт пользователя
асс = Account(login = "1234", password="6565")
alex.account = асс
alex.account.save()
# обновляем данные
alex.account.login = " qwerty"
alex.account.password = "123456"
alex.account.save()
Теперь рассмотрим совместную работу форм и моделей данных на примерах.
308 Глава 8
def
return render(request, "firstapp/aЬout.html")
def contact(request):
return render(request, "firstapp/contact.html")
- •
��ода д� q e!i"raJ!!
Здесь из моделей импортирован класс Person, а также добавлен импорт пакета redirect:
from .models iпport Person
получаем число записей о клиентах, которые хранятся в БД. Затем формируем словарь
context, в который включаем текстовую переменную my_text и объект people_count. На
последнем шаге через функцию render передаем словарь context на главную страницу
сайта (в шаблон Django firstapp/index.html).
Изменен код функции my_form о . Здесь проверяется условие, не нажал ли пользователь
кнопку Отправить в форме my_form (н request.method = "POST"). Если это условие вы
полняется, то проверяется валидность формы и данные сохраняются в БД. После этого
мы остаемся на той же странице, и форма для ввода данных о клиентах обновляется
(происходит перезагрузка формы).
Если клиент не вводил данные, то происходит простая загрузка формы. Здесь формиру
ется текстовая переменная ту_text и создается объект people, который получает все за
писи из табшщы БД со сведениями о клиентах. После этого создается объект form на
основе класса userform. Все данные, включая саму форму, упаковываются в словарь
310 Глава 8
{% extends "firstapp/base.html" %}
{% Ыосk title %}Главная страница{% endЫock title %}
{% Ыосk header %}Это главная страница сайта - index.html.{% endЫock header %}
{% Ыосk content%}
<div class="container-fluid my-2">
<div class="row">
<div class="col text-center">
<div>{{ my_text } }</div>
{% if people_kol >О%}
<h5>
Количество введенных пользователей - {{ people_kol }}
</h5>
{% endif %}
</div>
</div>
</div>
{% endЫock content %}
В этом шаблоне использованы теги Django для вьmода данных и теги Bootstrap для
форматирования страницы. В данном модуле сначала вьmодится значение переменной
{{my_text}}. Затем проверяется условие, есть ли в БД записи о клиентах, которые поль
зователь ввел через форму my_foпn, - {% if people_kol > о %}. Здесь people_kol- это объ
ект, в который из БД бьmо считано число записей о введенных в БД клиентах (передан
в шаблон из функции index). Если в БД имеются записи о клиентах, то их число будет
вьmедено в теге {{ people_kol J J.
Изменим шаблон формы для ввода данных о клиентах, т. е файл hello/templates/firstapp/
my_form.html (листинг 8.9).
{% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %}
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Формы и модели данных</h5>
<form method="POST">
{% csrf_token %}
<div class="form-group my-2">
{% for field in form %}
<div>{{field.laЬel_tag}}</div>
<div>{{field}}</div>
Модели данных Django 311
<div class="error">{{field.errors}}</div>
{% endfor %)
</div>
<input type="suЬmit" vаluе="Оrправить" >
{% if people.count >О%)
<h5>Список клиентов</h5>
<tаЫе class="taЫe taЫe-striped taЫe-bordered
text-start">
<thead>
<tr>
<th>№</th>
<th>ФИО клинта</th>
<th>Boзpacт</th>
</tr>
</thead>
<tЬody>
{% for person in people %)
<tr>
<td>{{ person.id ))</td>
<td>{{ person.name ))</td>
<td>{{ person.age ))</td>
</tr>
{% endfor %}
</tbody>
</tаЫе>
{% endif %}
</foпn>
</div>
{% endЫock content %)
Что ж, у нас все готово, и можно запустить приложение. При первом запуске мы полу
чим страницу, которая будет иметь вид, показанный на рис. 8.14.
Как видно из данного рисунка, на главной странице сайта отсутствует таблица со све
дениями о клиентах, т. к. в базе · данных еще нет ни одной записи. В главном меню
выберем опцию Форма, перейдем на страницу с формой для ввода данных о клиентах
и введем туда несколько записей (рис. 8.15).
1 Отправить 1
Возраст клиента:
1 Отправить j
Список клиентов
N!! ФИО КIIИНТа Возраст
1 Климов Игорь 63
Возраст кл»ента:
1 Отправить \
Список клиентов
N!! ФИО клинта Возраст
1 Климов Игорь 63
2 Житомирский Владимир 59
3 Шестов Алексей 55
4 Чурилко Николай 62
Рис. 8.17. Отображение введенной информации о клиентах, введенных в БД, в форме my_form.html
314 Глава 8
Если теперь обратиться к главной странице сайта, то на ней будет отображена инфор
мация о числе клиентов, введенных в БД (рис. 8.18).
Если мы теперь с использованием менеджера SQLiteStudio откроем содержимое табли
цы firstapp__person, то увидим в ней данные о клиентах, которые пользователь занес
в БД с помощью созданного нами приложения (рис. 8.19).
Рис. 8.18. Вид страницы index.html nосле ввода данных о нескольких пользователях
вВ
> [11 auth_user_user _permissions
> django_admin_log
> django_content_type
> В django_migrations
> � django_session
flrstapp_person
Как видно из данного рисунка, мы записали информацию в базу данных через интер
фейс НТМL-страницы. При этом бьmи задействованы два метода: Person.obj ects.all ()
(получение информации из БД) и klient.save() (запись информации о клиентах в Бд).
Обратите внимание, что в программном коде не бьm явно использован язык SQL. Хотя
фактически именно с его помощью бьmи вьmолнены операции взаимодействия с БД.
Просто это произошло в фоновом режиме благодаря моделям и менеджерам Django.
Модели данных Django 315
{% extends "firstapp/base.html" %}
{% Ыосk title %)Формы{% endЫock title %}
{% Ыосk header %)Изучаем формы Django{% endЬlock header %)
{% Ыосk content %)
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Редактирование данных</h5>
<form method="POST">
{% csrf_token %)
</form>
</div>
{% endЬlock content %)
{% extends "firstapp/base.html" %)
{% Ыосk title %)Формы{% endЬlock title %)
{% Ыосk header %)Изучаем формы Django{% endЬlock header %)
{% Ыосk content %)
<div class="container-fluid text-start my-2
border border-5 border-warning">
Модели данных Django 317
</tr>
{% endfor %}
</tЬody>
</taЬle>
{% endif %}
</form>
</div>
{% endЬlock content %}
Здесь в таблицу добавлена еще одна колонка, в которую вставлены две ссылки:
□ <а href="edit_form/{(person.id}}">Изменить</а> - обращение к функции редактирова
ния данных о клиентах (по сути, к форме edit_form.html);
□ <а href="delete/((person.id}J">Yдaлить</a> - обращение к функции удаления данных
о клиентах.
Затем внесем изменения в файл hello/firstapp/urls.py, сопоставим функции edit_form и ctelete
с маршрутами (листинг 8.13, изменения выделены серым фоном).
318 Глава В
Возра ст клиент а
:
1 Отправить 1
Список клиентов
N2 ФИО кпинта Воэраст
1 Климов Игорь 63
Загрузим форму для ввода данных. Теперь в таблице формы рядом с каждым объектом
(клиентом) появится колонка с двумя ссылками: Изменить и Удалить (рис. 8.20).
При нажатии на ссылку Изменить откроется страница для редактирования сведений
о клиенте. Изменим возраст одного из них с 63 на 65 лет (рис. 8.21).
После того как будет нажата кнопка Сохранить, мы вернемся на главную страницу,
где будет видно, что параметр клиента Возраст действительно изменился (рис. 8.22).
МенАе:М. ао.зраст
Введите возраст
65
Сохранить
Список пользователей
N2 ФИО кпинта
Климов Игорь 65
Рис. 8.22. Фрагмент главной страницы сайта после редактирования возраста клиента
320 Глава 8
11 li
WЫДВННЬI)( -------
С!руктур,1 Данные � "'14екщ ;
� 11!
� 11
dЬ (5Q!яо3)
dЬО !5Qlite3!
ra10•11 а а1а aeu� '11
� � ТабЛИUl>I (llJ id name acie
В auth_goup 1 1, Климо• Иrорь
·-65�
� rn auth_group_permissions
1>
2 59.
1> � auth__p<ermission 3 ssl
1> irn1] auth_user 4 62
1> if'!i! auth_user_groups
1> 1fд] auth_user_user_perrni ...
1> [�! django_admin_log
1> lE11J django_content_type
1> � django_migrations
1> � django_s�ssion
1> g_�t_o_
Рис. 8.23. Новое значение возраста клиента в БД после его редактирования на НТМL-странице
В озраст клиента,
Кли�нт с id=1
удален
Во3раст
Рис. 8.24. Фрагмент главной страницы сайта после удаления клиента с идентификатором id=l
Модели данных Django 321
Теперь нажмем на этой .странице на ссьmку Удалить для клиента Игорь Климов
(id= 1) - сведения о нем исчезнут из таблицы (рис. 8.24).
Можно убедиться в том, что клиент с id=l действительно удален из БД, если открыть
таблицу forstapp_person с помощью SQLiteStudio (рис. 8.25).
Итак, мы разобрались с тем, как с помощью моделей можно вносить данные в Бд,
редактировать и удалять информацию из БД через НТМL-шаблоны Django, не прибегая
к прямому использованию языка запросов SQL. Теперь рассмотрим возможности при
менения моделей и шаблонов для работы с изображениями и файлами.
m
1> autl,_user _user_permi...
m
1> django_admin_log ·
m
1> django_conlelt_type
m
1> django_migrations
1> django_session
Рис. 8.25. Клиента с id=l после его удаления через НТМL-страницу в БД больше нет
MEDIA URL = ,
�1EDIA_ROOT = os.path.join(BASE_DIR , .· )
Рис. 8.26. Задание базового URL и пути к папке с медиафайлами в модуле settings.ру
В этом программном коде добавлен импорт пакетов Django settings и static. Кроме то
го, к диспетчеру адресов urlpatterns добавлены ссылки на папки, в которых будут хра
ниться загруженные пользователями медиафайлы. Здесь задана инструкция if
settings.DEBUG, т. е. подключение этих адресов будет происходить только тогда, когда
выполняется разработка и отладка программного кода. Это означает, что указанные
URL-aдpeca будут использоваться только на этапе создания сайта на компьютере раз
работчика. При развертывании сайта на серверах в сети Интернет эти параметры можно
изменить.
На данном этапе все необходимые настройки выполнены, и нужно запустить следую
щие команды для миграции созданной модели в БД:
python manage.py makemigrations;
python manage.py migrate
Если теперь открыть БД, то можно увидеть, что там присутствует таблица firstapp_
image (рис. 8.27).
324 Глава 8
В D f3 !Ш DJ �� О 0 1 � iJIX Н
ldЬ
Внешний
Имя Типданных Уникальность
IС/\ЮЧ
1 id i intl!gl!r
2 title , varchar {100}
3 image ! varchar {100)
Здесь из модуля с моделями бьm импортирован класс rmage, и создана наша форма -
класс ImageForm на основе базового класса forms. ModelForm. Затем инициирован класс меtа,
в котором созданы объекты model и fields. Преимущество создания формы на основе
базового класса Django forms.ModelForm заключается в том, что форма автоматически
создаст поля на НТМL-странице в соответствии с полями модели Image, упомянутыми
в модуле model.py. В инструкции fields = '_all_' указано, что на форме нужно будет
отобразить все поля, которые присутствуют в модели. Поля можно бьmо задать и
в явном виде, как это делается показано в закомментированной строке.
Чтобы отобразить форму для загрузки изображений, создадим в папке с шаблонами
Dgango НТМL-страницу с именем hello/templates/firstapp/form_up_img.html (листинг 8.18).
Модели данных Django 325
{% extends "firstapp/base.htпй" %)
{% Ыосk title %)Формы{% endЫock title %)
{% Ыосk header %)Изучаем формы Django{% endЫock header %)
{% Ыосk content %)
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Формы - загрузка изображений</h5>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %)
<div class="form-group my-2">
{{ form.as_p ))
<button type="suЬmit">Зaгpyзить</button>
</div>
</form>
{% if my_img.count >О%)
<hЗ> {{my_text))</hЗ>
<tаЫе class="taЫe taЬle-striped taЫe-bordered
text-start">
<thead>
<tr>
<th>№</th>
<th>Что изображено</th>
<th>Имя файла</th>
<th>Изображение</th>
<th>Удаление</th>
<th>Показать</th>
</tr>
</thead>
<tbody>
{% for img in my_img %)
<tr>
<td>{{ img.id ))</td>
<td>{{ img.title ))</td>
<td>{{ img.image ))</td>
<td><img src="{{ img.image.url ))" alt="connect"
style="max-height:l00px"></td>
<td><a href="delete_img/{{img.id))">Yдaлить</a></td>
<td><a href="{{ img.image.url))"
class="btn btn-primary"
target="_Ьlank"> Показать</а></td>
</tr>
{% endfor %)
</tbody>
</tаЫе>
{% endif %)
</div>
{% endЫock content %)
326 Глава В
except Person.DoesNotExist:
return HttpResponseNotFound("<h2>0бъeкт не найден</h2>")
В этом модуле на первом шаге выполнен импорт модели и формы для работы с изо
бражениями:
from .models i.nport Image
from .forms irrport ImageForm
<!DOCTYPE html>
<html lang="en">
<head>
(% load static %}
<rneta charset="UTF-8">
<rneta name="viewport" content="width=device-width, initial-scale=l">
<link rel="stylesheet" href="/static/css/bootstrap.min.css" >
<script defer src="/static/js/bootstrap.bundle.min.js"></script>
<title>(% Ыосk title %}(% endЬlock title %}</title>
</head>
<body>
<div class="container-fluid р-1 bg-primary text-white text-center">
<div class="row">
<div class="col-2 ">
<img src="(% static 'images/SIS.jpg' %}">
</div>
<div class="col-10 ">
<hl>Это заголовок главной страницы сайта</hl>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="(% url 'index' %}">Главная страница</а>
<а href="{% url 'my_form' %}">Форма</а>
а nre =" % url 'form
<а href="{% url 'aЬout' %}">О компании</а>
<а href="{% url 'contact' %}">Контакты</а>
</hб>
</div>
</div>
<div class="container-fluid">
<div class="row text-center text-primary fs-1 fw-bold">
<div>(% Ыосk header%}(% endЬlock header %}</div>
</div>
<div class="row text-center text-body">
<div>(% Ыосk content%}(% endЬlock content %}</div>
</div>
</div>
Модели данных Django 329
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contriЬ.sessions',
'django.contriЬ.messages',
'django.contrib.staticfiles',
Итак, у нас все готово для того, чтобы продемонстрировать загрузку изображения в БД
нашего учебного сайта. Запускаем наш веб-сервер, выполнив команду
python manage.py runserver
то главная страниц
Изучаем модели Django
!!, "'""""'"""'"""""
Количество введенных пользов"'ате еи --�
Это подвал (footer) страниц сайта
Рис. 8.28. Опция в меню сайта для вызова формы загрузки изображений
330 Глава 8
- - - -- -
� страницы саита
(JljН\ИfRmwщца � ИМ6Pl'lllfИI оКQМПJНИИ Коитаm�
Изучаем формы Django
Формы - загрузка изображений
Описание изображения:
j загрузить 1
1 Загрузить 1
Загруженные изображения
N!! Что изо6ажено Имя файпа Изображение УАаnение Показать
Как видно из рис. 8.29, на форме имеется поле для ввода текста с описанием изображе
ния и две кнопки: Выберите файл - для выбора файла с изображением и Загру
зить - для загрузки изображения в БД сайта.
Если теперь выбрать какой-нибудь файл с изображением, ввести его описание и нажать
на кнопку Загрузить, то данный файл будет загружен на сайт, а имя загруженного
файла будет сохранено в БД. После этих действий страница будет выглядеть так, как
показано на рис. 8.30.
После этих действий в структуре проекта появятся две папки media/images/, где и будут
сохраняться загружаемые изображения, а имена загруженных файлов запишутся в БД
в таблицу firstapp/image (рис. 8.31).
Если нажать на кнопку Показать, то в браузере откроется новая вкладка, в которой
будет показана не «миниатюра», а полноразмерное изображение (рис. 8.32).
title file
1 Документ PDF files/Paздeл_l_б.pdf
Запись в
хранения
таблице БД
ф11й11ов
Рис. 8.31. Папки для хранения файлов и записи в таблице БД с именами загруженных файлов
0 Формы +
*
)( 0 АР_400.png (400х400) )( V
f- ➔ С ф 127.0.0.l:8000/media/images/AP_400.... � [В □ �
� А5иабилеты О Яндекс � Перевести G Gmail
# Загрузка файлов
class File(models.Model):
title = models.CharField(max_length=l00,
verbose_name= "Oпиcaниe файла",)
file = models.FileField(upload_to= 'files',
verbose_nаmе= "Файл PDF'',
null=Тrue, Ыaпk=True)
def str (self):
return self.title
□ file - поле для хранения имени файла (тип поля varchar - текстовое поле перемен
ной длины с максимальным числом символов, равным 100).
Поскольку file - это текстовое поле, то в нем будет храниться только имя файла, но
не сам файл.
аt
Структура Д
1...-"'С..�•---'--""'--'--�----.:..:....:.......w......:.--'-1
'
Е1 ! L'J
Имя
1 id integer
2 title varchar (100)
3 file varchar (100)
Теперь создадим форму, которая будет принимать файл в качестве входных данных от
пользователя. Откроем файл hello/firstapp/forms.py и напишем в нем код из листинга 8.24.
Здесь из моделей был импортирован класс File, затем в классе меtа на его основе созда
ны объекты moctel и fielcts (поля). В объект fielcts будут загружены все поля из модели
File.
Теперь создадим представление (view) для обработки запросов, связанных с загрузкой
файлов. Откроем модуль hello/firstapp/views.py и напишем в нем код листинга 8.25.
file_obj = File.objects.all()
context = ( 'my_text': my_text, 11file_obj 11: file_obj, 11 form 11: form}
return render(request, 'firstapp/form_up_pdf.html', context)
# удаление файлов из БД
def delete_pdt(request, id):
try:
pdf = File .objects.get(id=id)
pdf .delete()
return redirect('form_up_pdf')
exce.pt Person.DoesNotExist:
return HttpResponseNotFound( 11<h2>0бъект не найден</h2> 11)
В этом модуле на первом шаге вьmолнен импорт модели и формы для работы с фай
лами:
from .models import File
from .forms import FileForm
Затем создана функция для загрузки файлов - ctef form_up_pdf(request). В этой функции
проверяется условие, поступил ли запрос от пользователя на загрузку файла
(if request.method == 'POST'). Если такой запрос поступил, то на основе класса FileForm
создается объект form, который получает запрос от пользователя на сохранение данных
о файле (request.POsт), и сам загружаемый файл (request.FILES). Если форма не содержит
ошибок, то введенные пользователем данные сохраняются (form.save). После этого про
исходит обновление формы для загрузки файлов.
Если форма вызывается первый раз, т. е. поступил запрос GET, то создаются:
□ текстовая переменная my_text;
□ объект form, который создается на основе класса FileForm (т. е. сама форма);
□ объект file_obj, который принимает из БД все сведения о загруженных файлах.
Затем создается объект context, в который в виде словаря передаются объекты my_text,
file_obj и form. После этого вызывается шаблон form_up_pdf.html, в который передаются
все данные через объект context.
Чтобы отобразить форму для загрузки файлов, создадим в папке с шаблонами Django
НТМL-страницу с именем hello/templates/firstapp/form_up_pdf.html (листинг 8.26).
(% extends 11firstapp/base.html 11 %)
(% Ыосk title %)Формы(% endЬlock title %}
(% Ыосk header %)Изучаем формы Django(% endЬlock header %}
(% Ыосk content %}
<div class= 11 container-fluid text-start my-2
border border-5 border-warning 11 >
<h5>Формы - загрузка файлов</h5>
<form method= 11POST 11 enctype=11 multipart/form-data 11 >
(% csrf_token %}
<div class=11form-group my-2 11 >
( ( form.as_p } }
Модели данных Django 335
<button type="suЬmit">Зaгpyзить</button>
</div>
</form>
{% if file_obj.count >О%)
<hЗ> {{my_text))</hЗ>
<tаЫе class="taЫe taЬle-striped taЫe-bordered
text-start">
<thead>
<tr>
<th>№</th>
<th>Оnисание файла</th>
<th>Имя файла</th>
<th>Удаление</th>
<th>Показать</th>
</tr>
</thead>
<tЬody>
{% for obj in file_obj %)
<tr>
<td>{{ obj.id ))</td>
<td>{{ obj.title ))</td>
<td>{{ obj.file ))</td>
<td><a href="delete_pdf/{{obj.id))">Yдaлить</a></td>
<td><a href="{{ obj.file.url))" class="btn Ьtn-primary"
target="_Ыank"> Показать</а></td>
</tr>
{% endfor %)
</tbody>
</tаЫе>
{% endif %)
</div>
{% endЫock content %)
□ { % if file_obj . count > о %) - для показа файлов, которые пользователь загрузил в БД.
Здесь тег csrf_token защитит форму от вредоносных данных, а form.as_p отобразит поля,
предназначенные для ввода данных, в виде параграфов.
ПРИМЕЧАНИЕ
Здесь используется опция enctype = "multipart/form-data", которая позволяет отправлять
файлы через РОSТ-запросы. Без активации этой опции пользователь не может отправить
файл через запрос POST. Эту опцию необходимо обязательно включать в формы работы
с файлами и изображениями.
в отдельной вкладке браузера. Иначе говоря, в данной форме можно загружать файлы
PDF, просматривать их и удалять с сайта.
Теперь, когда и форма, и обработчик формы готовы, сопоставим форму с ее URL
aдpecoм в urls.py. Открываем модуль hello/firstapp/urls.py и добавляем в него две строки
(листинг 8.27, изменения выделены серым фоном).
В этом программном коде была сопоставлена функция загрузки файлов (views. form_
upydf) с URL-aдpecoм шаблона НТМL-страницы, которая отображает саму форму
('form_up_pdf/'), и функция удаления файла (views.delete_pdf) с ее URL-aдpecoм
(form_upydf/delete_pdf/<int:id>/). В этой инструкции в функцию delete_pdf передается
идентификатор той записи, которую нужно удалить из БД.
Остался последний шаг - необходимо включить вызов формы form_up_pdf.html из меню
главной страницы сайта. Для этого в базовый шаблон сайта hello/templates/firstapp/base.html
добавим одну строку - ссылку на страницу form_up_pdf.html. В листинге 8.28 приведен
фрагмент кода модуля base.html, где· добавленная строка выделена серым фоном.
Итак, у· нас все готово для того, чтобы продемонстрировать загрузку файлов PDF в БД
нашего учебного сайта. Запускаем наш веб-сервер командой
python manage.py runserver
Модели данных Django 337
На главной странице сайта в главном меню появилась новая опция Файлы (рис. 8.34).
Если теперь щелкнуть мышью на ссьmке Файлы, то откроется форма для загрузки
файлов (рис. 8.35).
Рис. 8.34. Опция в меню сайта вызова формы для загрузки файлов
1 Загрузить 1
Как видно из данного рисунка, на форме имеется поле для ввода текста с описанием
файла и две кнопки: Выберите файл - для выбора файла и Загрузить - для загрузки
файла в БД сайта.
Если теперь выбрать какой-нибудь файл (документ в формате PDF), ввести его описа
ние и нажать на кнопку Загрузить, то данный файл будет загружен на сайт, а имя
загруженного сайта будет сохранено в БД. После этих действий страница будет выгля
деть так, как показано на рис. 8.36.
После этих действий в структуре проекта появится папка для хранения файлов
media/files/, где и будут сохраняться загружаемые файлы, а имена загруженных файлов
будут записаны в БД в таблицу firstapp/file (рис. 8.37).
338 Глава 8
1 Заrрузить 1
Загруженные файлы
N! Оnиса"ие файла Имя файла У111апе"ие Пока1ать
1111111
+----�
rrmz::r
1 Документ PDF files/Paздeл_1_6.pd
f }'д1И!.!1I!,
Данные
Папки для
хранения
файлов
0 Формы Х 0 Раздел_l_б.рdf х + V
f- ➔ С (D 127.0.0.1:8000/media/files/Paздeл_l_б.pdf
# Загрузка видеофайлов
class VideoFile(models.Model):
title = models.CharField(max_length=l00,
verbose_name="Onиcaниe файла",)
file = models.FileField(upload_to='videos',
vеrЬоsе_nаmе="Видеофайл",
null=True, Ыank=True)
340 Глава 8
obJ_video = models.Manager()
def str (self):
return self.title
Здесь из моделей был импортирован класс VideoFile, затем в классе меtа на его основе
созданы объекты model и fields (поля). В объект fields будут загружены все поля из
модели VideoFile.
Теперь создадим представление (view) для обработки запросов, связанных с загрузкой
файлов. Откроем модуль hello/firstapp/views.py и напишем в нем код листинга 8.31.
Модели данных Django 341
В этом модуле на первом шаге выполнен импорт модели и формы для работы с видео
файлами:
from .models import VideoFile
from .forms import VideoForm
Затем создана функция для загрузки файлов- def form_up_video(request). В этой функ
ции проверяется условие, поступил ли запрос от пользователя на загрузку видеофайла
(if. request.method == 'POST'). Если такой запрос поступил, то на основе класса VideoForm
создается объект foпn, который получает запрос от пользователя на сохранение данных
о видеофайле (request.POsт), и сам загружаемый файл (request.FILES). Если форма не со
держит ошибок, то вьmолняется сохранение введенных пользователем данных
(form.save). После этого происходит обновление формы для загрузки видеофайлов.
Если форма вызывается первый раз, т. е. поступил запрос GET, то создаются:
□ текстовая переменная my_text;
□ объект foпn, который создается на основе класса victeoForm (т. е. сама форма);
□ объект file_obj, который принимает из БД все сведения о загруженных файлах.
Затем создается объект context, в который в виде словаря передаются объекты: my_text,
file_obj, form. После этого вызывается шаблон form_up_video.html, в который передаются
все данные через объект context.
Чтобы отобразить форму для загрузки видеофайлов, создадим в папке с шаблонами
Django НТМL-страницу с именем hello/templates/firstapp/form_up_video.html (листинг 8.32).
342 Глава В
{% extepds "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЫock header %}
{% Ыосk content %}
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Формы - загрузка видеофай.лов</h5>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group my-2">
{{ form.as_p }}
<bu�ton type="suЬmit">Зaгpyзить</button>
</div>
</form>
{% if file_obj.count >О%}
<hЗ> {{my_text}}</hЗ>
<tаЫе class="taЫe taЫe-striped taЫe-bordered
text-start">
<thead>
<tr>
<th>№</th>
<th>Описание файла</th>
<th>Имя фай.ла</th>
<th>Удаление</th>
<th>Показать</th>
</tr>
</thead>
<tЬody>
{% for obj in file_obj %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.file }}</td>
<td><a href="delete_video/{{obj.id}}">Yдaлить</a></td>
<td>
<video width="320" height="240" controls>
<source src="{{obj.file.url}}"
type="video/rrp4">
</video>
</td>
</tr>
{% endfor %}
</tbody>
</tаЫе>
{% endif %}
</div>
{% endЫock content %}
Модели данных Django 343
Атрибут loop дает возможность автоматически повторять видео - заставлять его вос
производиться снова каждый раз, когда показ завершится. Например:
<video
controls
loop
src="weekend.rrp4"
poster="benefits-of-coding. jpg"
></video>
Атрибуты width и height дают возможность указать ширину и высоту видео в пикселах.
Он принимает только абсолютные значения, например:
<video
controls
loop
autoplay
src="weekend.rrp4"
width="350px"
height="250px"
poster="benefits-of-coding. jpg"
></video>
Атрибут muted можно использовать для того, чтобы браузер не воспроизводил звуко
вую дорожку, связанную с видео. Например:
<video
controls
loop
autoplay
muted
src="weekend.rrp4"
width="350px"
height="250px"
poster="benefits-of-coding. jpg"
></video>
Атрибут preload "подскажет" браузеру, следует ли загружать видео при загрузке стра
ницы. Этот атрибут имеет решающее значение для взаимодействия с пользователем.
Доступны следующие значения этого атрибута:
□ none - указывает, что видео не будет загружаться, пока пользователь не нажмет
кнопку воспроизведения;
Модели данных Django 345
□ auto - указывает, что видео должно загружаться, даже если пользователь не нажи
мает кнопку воспроизведения;
□ metadata - указывает, что браузер должен собирать метаданные, такие как длина,
размер, продолжительность и т. д.
Вот пример использования этого атрибута:
<video
controls
loop
autoplay
muted="true"
preload= "metadata"
src="weekend.mp4"
width="350px"
height="250px"
poster="benefits-of-coding.jpg"
></video>
Теперь, когда и форма, и обработчик формы готовы, сопоставим форму с ее URL
aдpecoм в urls.py. Открываем модуль hello/firstapp/urls.py и добавляем в него две строки
(листинг 8.33, изменения выделены серым фоном).
Итак, у нас все готово для того, чтобы продемонстрировать загрузку видеофайлов в БД
нашего учебного сайта. Запускаем наш веб-сервер, выполнив команду
python manage.py runserver
На главной странице сайта в главном меню появилась новая опция Видео (рис. 8.39).
Если теперь щелкнуть мышью на ссылке Видео, то откроется форма для загрузки
видеофайлов (рис. 8.40).
Рис. 8.39. Опция в меню сайта вызова формы для загрузки видеофайлов
/ Загрузить /
Как видно из рис. 8.40, на форме имеется поле для ввода текста с описанием файла
и две кнопки: Выберите файл - для выбора файла, Загрузить - для загрузки файла
в БД сайта.
Если теперь выбрать какой-нибудь видеофайл (в формате МР4), ввести его описание
и нажать на кнопку Загрузить, то данный файл будет загружен на сайт, а имя загру
женного сайта будет сохранено в БД. После этих действий страница будет выглядеть
так, как показано на рис. 8.41.
j Зarpyзиri. j
Загруженные видео файлы
Оnмсание
N2 фай11а Имя ♦•КЛ•
1 Конструктор videos/small.mp4 У�
Данные � Индексы
Табличный вид ...._Форма
__,_-"'----- --------il
1
хранения
файлов
Рис. 8.42. Папки для.хранения видеофайлов записи в таблице БД с именами загруженных файлов
348 Глава В
После этих действий в структуре проекта будет создана папка для хранения видеофай
лов media/videos/, где и будут сохраняться загружаемые файлы, а имена загруженных
файлов будут записаны в БД в таблицу firstapp/videofile (рис. 8.42).
Таким образом, мы реализовали загрузку на сайт видеофайлов, просмотр видео и их
уд.аление с сайта. Теперь рассмотрим вьmолнение аналогичных действий с аудиофай
лами.
# Загрузка аудиофайлов
class AudioFile(models.Model):
title = models.CharField(max_length=l00,
verbose_name="Onиcaниe файла",)
file = models.FileField(upload_to= 'audios',
vеrЬоsе_nаmе= "Аудиофайл",
null=True, Ыank=Тrue)
obj_audio = models.Manager()
def str (self):
return self.title
Здесь из моделей бьm импортирован класс AudioFile, затем в классе меtа на его основе
созданы объекты model и fields (поля). В объект fields будут загружены все поля из
модели AudioFile.
Теперь создадим представление (view) для обработки запросов, связанных с загрузкой
файлов. Откроем модуль hello/firstapp/views.py и напишем в нем код листинга 8.37.
# Загрузка аудиофайлов
def form_up_audio(request):
if request.method == 'POST':
form = AudioForm(request.POST, request.FILES)
if form.is_valid():
form.save()
my_text = 'Загруженные аудиофайлы'
form = AudioForm()
file_obj = AudioFile.obj_audio.all()
context = {'my_text': my_text, "file_obj": file_obj, "form": form)
return render(request, 'firstapp/form_up_audio.html', context)
# удаление аудиофайлов из БД
def delete_audio(request, id):
try:
audio = AudioFile.obj_audio.get(id=id)
audio.delete()
return redirect('form_up_audio')
350 Глава 8
except Person.DoesNotExist:
return HttpResponseNotFound("<h2>0бъект не найден</h2>")
В этом модуле на первом шаге выполнен импорт модели и формы.для работы с аудио
файлами:
from .models import AudioFile
from .forms inport AudioForm
Затем создана функция для загрузки файлов- def form_up_audio(rE;quest). В этой функ
ции проверяется условие, поступил ли запрос от пользователя на загрузку аудиофайла
(if request.method == 'POST'). Если такой запрос поступил, то на основе класса AudioForm
создается объект form, который получает запрос от пользователя на сохранение данных
об аудиофайле (request.POST) , и сам загружаемый файл (request.FILES). Если форма не
содержит ошибок, то выполняется сохранение введенных пользователем данных
(form.save). После этого происходит обновление формы для загрузки аудиофайлов.
Если форма вызывается первый раз, т. е. поступил запрос GET, то создаются:
□ текстовая переменная my_text;
□ объект form, который создается на основе класса AudioForm (т. е. сама форма);
□ объект file_obj, который принимает из БД все сведения о загруженных файлах.
Затем создается объект context, в который в виде словаря передаются объекты my_text,
file_obj, form. После этого вызьmается шаблон form_up_audio.html, в который передаются
все данные через объект context.
Чтобы отобразить форму для загрузки аудиофайлов, создадим в папке с шаблонами
Django НТМL-страницу с именем hello/templates/firstapp/form_up_audio.html (листинг 8.38).
{% extends "firstapp/base.html" %}
{% Ыосk title %}Формы{% endЫock title %}
{% Ыосk header %}Изучаем формы Django{% endЫock header %)
{% Ыосk content %}
<div class="container-fluid text-start my-2
border border-5 border-warning">
<h5>Формы - загрузка аудиофайлов</h5>
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div class="form-group my-2">
{ { form.as_p }}
<button type="suЬmit">Зaгpyзить</button>
</div>
</form>
{% if file_obj.count >О%}
<hЗ> {{my_text}}</hЗ>
<tаЫе class="taЫe taЫe-striped taЬle-bordered
text-start">
<thead>
<tr>
<th>№</th>
Модели данных Django 351
<th>Описание файла</th>
<th>Имя файла</th>
<th>Удаление</th>
<th>Прослушать</th>
</tr>
</thead>
<tЬody>
{% for obj in file_obj %}
<tr>
<td>{{ obj.id }}</td>
<td>{{ obj.title }}</td>
<td>{{ obj.file }}</td>
<td><a href="delete_audio/{{obj.id})">Yдaлить</a></td>
<td>
<audio controls>
<source src="{{obj.file.url}}"
type="audio/mpЗ">
</audio>
</td>
</tr>
{% endfor %}
</tbody>
</tаЫе>
{% endif %}
</div>
{% endЫock content %}
Атрибут loop дает возможность автоматически повторять аудио - заставлять его вос
производиться снова каждый раз, когда оно завершится. Например:
<audio
controls
loop
src;"weekend.mpЗ"
></audio >
Атрибут muted можно использовать для того, чтобы браузер не воспроизводил звук.
Например:
<audio
controls
loop
autoplay
muted
src;"weekend.mpЗ"
></audio >
Атрибут preload "подскажет" браузеру, следует ли загружать аудио при загрузке стра
ницы. Этот атрибут имеет решающее значение для взаимодействия с пользователем.
Возможны следующие значения атрибута предварительной загрузки:
□ none - указывает, что аудио не будет загружаться, пока пользователь не нажмет
кнопку воспроизведения;
Модели данных Django 353
□ auto - указывает, что аудио должно загружаться, даже если пользователь не нажи
мает кнопку воспроизведения;
□ metadata - указывает, что браузер должен собирать метаданные, такие как размер,
·продолжительность и т. д.
Вот пример использования этого атрибута:
<audio
controls
loop
autoplay
muted="true"
preload="metadata"
src= "weekend.rnpЗ"
></audio >
Итак, у нас все готово для того, чтобы продемонстрировать загрузку аудиофайлов в БД
нашего учебного сайта. Запускаем наш веб-сервер, выполнив команду
python manage.py runserver
На главноn странице сайта в главном меню появилась новая опция Аудио (рис. 8.43).
Если теперь щелкнуть мышью на ссьmке Аудио, то откроется форма для загрузки
аудиофайлов (рис. 8.44).
Рис. 8.43. Опция в меню сайта вызова формы для загрузки аудиофайлов
а и
! з груз ть 1
Как видно из данного рисунка, на форме имеется поле для ввода текста с описанием
файла и две кнопки: Выберите файл - для выбора файла, Загрузить- для загрузки
файла в БД сайта.
Если теперь выбрать какой-нибудь аудиофайл (в формате МРЗ), ввести его описание
и нажать на кнопку Загрузить, то данный файл будет загружен на сайт, а имя загру
женного сайта будет сохранено в БД. После этих действий страница будет выглядеть
так, как показано на рис. 8.45.
После этих действий в структуре проекта появится папка для хранения аудиофайлов
media/audios/, где и будут сохраняться загружаемые файлы, а имена загруженных файлов
будут записаны в БД в таблицу firstapp/audiofile (рис. 8.46).
\ Загрузить 1
id titJe file
1 11 Гаити
Папки для
хранения
Запись в
файлов
таблицеБД
Рис. 8.46. Папки для хранения аудиофайлов записи в таблице БД с именами загруженных файлов
356 Глава В
11(:
\
Location: C:\Users\Anatoly\Pycf1armProjects\\/lJorld_book�
Location: C:\Users\Anatoly\PycharmProjects\World_books\\'env
Теперь загрузим фреймворк Django, выполнив в окне терминала PyCharm команду pip
install Dj ango.
После этого фреймворк Django появится в списке доступных библиотек (рис. 9.2).
В результате вьmолнения этой команды в папке World_books проекта PyCharm будет соз
дана новая папка WebBooks проекта Django (рис. 9.4).
Рис. 9.3. Создание нового проекта Django с именем WeЬBooks в окне терминала РуСhаггп
11 Wortd_Ьooks II vVebBooks
t
v
tiJ Project .. о -
fУ
..
II World_Ьooks
► llven,,
..;· IIWebB�ok�
У 11 �VebBooks Рис. 9.4. Структура файлов
iG, _in1t_.py
проекта Django с именем
WebBooks
iG, asg1.py
iG, sett1ngs.py
iG, urls.py
[+,vsgi.py
iG, manage.py
► 11111 Eл1:ernal Libraries
&"
О Scratches and Co11sole,
Как видно из рис. 9.4, головная папка проекта WebBooks включает одну вложенную пап
ку WebBooks - это ключевой каталог нашего проекта, в котором находятся следующие
файлы:
□ settings.py- содержит все настройки проекта (здесь мы регистрируем приложения,
задаем размещение статичных файлов, настраиваем базу данных и т. п.);
□ urls.py- задает ассоциации интернет-адресов (URL) с представлениями views (этот
файл может содержать все настройки URL, но обычно его делят на части - по од
ной на каждое приложение, как будет показано далее);
□ asgi.py и wsgi.py- предназначены для организации связи между Djаngо-приложением
и внешним веб-сервером (мы задействуем эти файлы позже, когда будем рассматри
вать развертывание сайта в Интернете).
360 Глава 9
Кроме вложенной папки WebBooks, в головной папке проекта WebBooks имеется также
файл manage.py. Это скрипт, который обеспечивает создание приложений, работу с ба
зами данных, запуск отладочного сервера. Именно этот скрипт потребуется на сле
дующем шаге для создания приложения.
Итак, создадим приложение с именем catalog. Для этого сначала необходимо из прило
жения PyCharm (внешняя папка World_books) перейти в приложение Django- войти во
вложенную папку WebBooks, в которой находится скрипт manage.py. Для этого в окне
терминала PyChann выполните команду cct weьвooks (рис. 9.5).
Вот теперь, находясь в папке проекта Django с именем WebBooks (той, где Р.азмещен
скрипт manage.py), создадим приложение catalog. Для этого выполним следующую ко
манду (рис. 9.6):
python manage.py startapp catalog
В результате в папке верхнего уровня WebBooks появится новая папка с именем catalog,
а в ней и будут содержаться файлы нашего приложения catalog (рис. 9.7).
Эти файлы предназначены для выполнения следующих функций:
□ папка migrations - хранит миграции (файлы, которые позволяют автоматически об
новлять базу данных по мере изменения моделей данных);
□ «пустой» файл _init_.py - его присутствие позволяет Django и Python распознавать
папку catalog как папку с модулями Python, что дает возможность использовать
объекты этих модулей внутри других частей проекта;
□ файл admin.py - содержит информацию с настройками административной части
приложения;
□ файл apps.py - предназначен для регистрации приложений;
□ файл models.py - содержит описание моделей данных, с которыми будет работать
приложение;
Пример создания веб-сайта на Django 361
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
362 Глава 9
Теперь следует указать базу данных для нашего проекта. По возможности име� смысл
использовать одну и ту же базу данных, как в процессе разработки проекта, так и при
размещении его в Интернете. Это позволит исключить возможные различия в поведе
нии проекта после его публикации.
Однако для нашего проекта мы воспользуемся базой данных SQLite, потому что по
умолчанию приложение уже настроено для работы с ней. В этом можно убедиться, от
крьm соответствующий раздел в файле settings.py (рис. 9.9).
Как можно видеть, к проекту подключен движок БД SQLite, а файл, который содержит
сами данные, носит имя db.sqliteЗ.
Файл settings.py также служит и для выполнения некоторых других настроек (значения
их по умолчанию показаны на рис. 9.1 О):
Пример создания веб-сайта на Django 363
TIME_ZONE = 'Europe/Moscow'
USE IlBN = True
364 Глава 9
0 127.0.0.1:8000 )(
(- ➔ С ф 127.0.0.1:8000
� Аsиабилетъ1 О Яндекс � Переее-с:тм
1
,'\,;MV•l,1' 'fMpr;l:,l'IИ( [Jj lfl()<J
Имя пользователя:
/ anatoly
Пароль;
войти
Рис. 9.13. Вызов административной страницы сайта Рис. 9.14. База данных
проекта WebBook dЬ.sqliteЗ
После этого можно проверить, что эти пакеты действительно загру�ены в проект
(рис. 9.15).
После этого пакет django-cleanup нужно подключить к проекту. Открываем файл
WebBooks/WebBooks/settings.py и в блок INSTALLED_APPS добавляем строку из листинга 9.5
(изменения выделены серым фоном).
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
STATIC_URL = 'static/'
DIR / "static"),
Здесь определена папка, в которой будут храниться статические файлы (static). В строке
(MEDIA_URL) задан URL-aдpec, в строке (МEDIA_Rooт) - путь к папке media, в которой будут
храниться медиафайлы пользователей. Если в моделях мы укажем имя папки для хра
нения изображений uploact_to='images', а здесь в настройках задали папку для хранения
медиафайлов media, то в нашем случае все изображения будут размещены по следую
щему пути: /media/images/.
Нам не нужно создавать папки media и images, Django создаст их автоматически, как
только пользователь выполнит процедуру загрузки первого изображения. А вот папки
WebBooks/static и WebBooks/templates нужно будет создать самостоятельно. Создадим две
новые папки (static, templates) и скорректируем содержимое модуля settings.py. Изменения,
внесенные в модуль settings.py, показаны на рис. 9.16.
Теперь в настройках нашего проекта нужно выполнить еще одно действие - указать
расположение папки templates с шаблонами НТМL-страниц. Снова открьmаем модуль
WebBooks/WebBooks/settings.py и добавляем в него код листинга 9.7 (выделено серым фо
ном), показано на рис. 9.17.
TEМPLATES = [
{
'ВACKEND': 'django.template.backends.django.DjangoTerrplates',
'DIRS' : [!ГЕМРLАТЕ_!?IR, ] ,
'АРР DIRS': True,
Пример создания веб-сайта на Django 369
'OPTIONS' : {
'context_processors':
'django.ternplate.context_processors.debug',
'django.ternplate.context_processors.request',
'django.contrib.auth.context_processors.auth',
'django.contrib.messages.context_processors.messages',
],
),
),
Теперь нужно скачать файлы Bootstrap и загрузить их в папку static нашего проекта.
Скачиваем готовые файлы с официального сайта по следующей ссьmке:
https://getbootstrap.com/docs/5.2/getting-started/download/.
После скачивания вы получите архивированный ziр-файл, в имени которого будет от
ражена текущая версия фреймворка, например bootstrap-5.2.3-dist.zip. После распаковки
архива будут созданы две папки: css - с файлами стилей, и js - с Jаvа-скриптами. Эти
две папки нужно перенести в ваш проект в каталог static, там же создадим пустую папку
images, где будут храниться статичные изображения, загружаемые на этапе проектиро
вания сайта (рис. 9 .18).
81 World_Ьooks 81 WebBooks 1
t [!iJ ProJedr @ (1 -
·о
о:.. 11 World_Ьooks
1
,..... ► 81 venv Рис. 9.18. Загрузка файлов
" 81 1NebBooks Bootstrap 5
в папку static проекта
► 81 catalog
► 81 media
Т 81 static
► 81css •----
811mages ----
► 8ljs -----
Author (аеторJ
1
--э- name :String {ФИО}
8ook (кнмrа)
1 date_ot_blrth :String {родился)
tille :String(книга)
aЬout:String (об авторе)
author(аатор)
<Е- +_str_: StString
annqtation :String (аннотация!
,,. .
-Е--
Language {Я3ык) +- 1
.,
Genre (жанрJ
+_str_: stStrin&
. ➔ name:String (жанр)
+_str_: StString
Вooldnstance {зсемпмр}
1
➔ unic.ueld:String
Language {язbll(t
name:String (Я3ык)
!
due_Ьack:String(дата аозарата)' �
status:(состояние) +_str_: St String
fE-
Ьооk: (книга}
Status (с:остоянме}
+_str_: StString..
➔ name:String (состояние)
Из данного рисунка видно, что мы сформировали перечень таблиц, которые будут соз
даны в БД, перечень и типы полей, которые будут в каждой таблице, определили связи
между таблицами.
Пример создания веб-сайта на Django 373
сколько книг). В нашем приложении для сайта «Мир книг» мы будем использовать
этот тип поля аналогично типу ForeignKey для описания отношений между группами.
Эти типы полей имеют параметр on_delete, определяющий, что происходит, когда
связанная запись удаляется (например, значение models.SET_NULL просто удаленно
установило бы значение поля в NULL).
Существует много других типов полей, включая поля для разных типов чисел (большие
целые числа, малые целые числа, дробные). А также поля с логическими значениями,
URL-адресами, символами «slugs», уникальными идентификаторами, временем, датами
и т. д. Эти поля мы достаточно подробно описали, когда рассматривали формы Django.
class Meta:
verbose name = "Название книги"
ПРИМЕЧАНИЕ
Полный список метаданных доступен в документации по Django.
При вьшолнении этого кода из БД будут выбраны все книги из жанров: фантастика,
научная фантастика.
Рис. 9.20. Файл-шаблон models.py для проектирования моделей данных сайта «Мир книг»
Добавим в файл models.py строку импорта класса reverse, который обеспечит получение
абсолютных URL-aдpecoв (листинг 9.8, строка выделена серым фоном).
# жанры книг
class Genre(models.Model):
name = models.CharField(max_length=200,
help_text=" Введите жанр книги",
verbose_name= "Жанр книги")
def str (self):
return self.name
Поле name будет использоваться для описания жанра книги, оно ограничено 200 симво
лами и имеет текст подсказки: help_text. В качестве удобно читаемого имени
(verbose_name) указано значение "Жанр книги", поэтому именно оно будет выводиться на
экран в формах рядом с полем name. В конце модели объявлен метод _str_(), возвра
щающий имя жанра, которое будет внесено в конкретную запись.
Пример создания веб-сайта на Django 381
# язык книги
class Language(models.Model):
name = models.CharField(max_length=20,
help_text=" Введите язык книги",
verbose_nаmе="Язык книги")
def str (self):
return self.name
Поле name будет использоваться для хранения языка книги, оно ограничено 20 символа
ми и имеет текст подсказки: help_text. В качестве удобно читаемого имени (verbose_name)
указано значение "Язык книги", поэтому именно оно будет выводиться на экран в формах
рядом с полем narne. В конце модели объявлен метод _str_(), возвращающий наимено
вание языка книги, которое будет внесено в конкретную запись.
# издательство
class PuЬlisher(models.Model):
name = models.CharField(max_length=20,
help_text=" Введите наименование издательства",
vеrЬоsе_nаmе="Издательство")
def str (self):
return self.name
Как можно видеть в данном листинге, модель PuЫisher содержит одно текстовое поле
(типа CharField), которое назьtвается name. Это поле будет использоваться для хранения
наименования издательства, оно ограничено 20 символами и имеет текст подсказки:
help_text. В качестве удобно читаемого имени (verbose_narne) указано значение "Издатель
ство", поэтому именно оно будет выводиться на экран в формах рядом с полем name.
В конце модели объявлен метод _str_(), возвращающий наименование издательства,
которое будет внесено в конкретную запись.
382 Глава 9
# авторы
class Author(models.Model):
first_name = models.CharField(rnax_length=lOO,
hеlр_tехt="Введите имя автора",
verbose_nаmе="Имя автора")
last_narne = models.CharField(rnax_length= lOO,
hеlр_tехt="Введите фамилию автора",
verbose_nаmе="Фамилия автора")
date_of_Ьirth = models.DateField(
hеlр_tехt="Введите дату рождения",
verbose_name= "Дaтa рождения",
null=Тrue, Ыank=Тrue)
aЬout = models.TextField(help_text="Bвeдитe сведения об авторе",
vеrЬоsе_nаmе="Сведения об авторе")
photo = models.IrnageField(upload_to='irnages',
hеlр_tехt="Введите фото автора",
verbose_narne="Фoтo автора",
null=Тrue, Ыank=Тrue)
def str (self) :
return self.last name
Как можно видеть из данного листинга, модель Author содержит текстовые поля (типа
CharField) для хранения имен и фамилий авторов. Эти поля ограничены 100 символами,
имеют текст подсказки: help_text и удобно читаемые имена (verbose_:name). Поле для вво
да даты (date_of_Ьirth типа DateField) предназначено для хранения даты рождения авто
ра книги. Это поле может содержать пустое значение (null=True), т. е. не обязательно
для заполнения. В модели имеется поле для ввода сведений об авторе ( aЬout типа
тextField) и для фотографии или портрета автора (photo типа IrnageField). Поле photo
имеет атрибут upload_to='irnages'. Это означает, что все файлы с фотографиями или
портретами авторов будут автоматически сохраняться в папку проекта с именем images.
Meтoд _str_() будет возвращать фамилию автора.
Вооk (Ка•r•)
id title
1 c�un_ld
Gеоп (Жаиры)
id aame
1
1 Книга 1 J � 1 Пixm
- По:пu
-
2 Кияrа2 2 2
l:J
3 Кю!n3 3 3 Фашастш.:а
1
4 Кявrа4 3
Вооk(Кавrв}
w Jitk
1 ЫJ1111&&• (Я,sw.1.в)
w 1WВ
1
�-kt
1 Киша 1 1 1 AигшdkJWII
2 Киига2 2 - 2 Немецхий
--
1
3 Киига3 3 3 Руссай
с,; 1
4 Киига4 3
Вооk(Кввrв)
ill.
1
ш�
Кииnl
1
W1PU _kl
1 -
м1
1
--
PuЫisller (И3Дательство)
Ridero
1
2 Кииrа2 2 -- 2 Ли11'ес
-
1
3 Кииrа3 3 3 бХВ Пет�:рбург
ф 1
4 Кииn4 з
Рис. 9.23. Связь «один ко многим» между издательствами и книгами
Несколько сложнее обстоит дело с книгами и их авторами. Каждая книга может быть
написана несколькими авторами, но и автор может написать несколько книг (как само
стоятельно, так и в соавторстве). Значит, здесь присутствует_ связь «многие ко многим»,
а для реализации такой связи необходим новый объект в модели, или новая связующая
таблица в базе данных (рис. 9.24).
Ьш/k_ author
Вооk(Кввгв) Autbor (Авторы)
�_id A!l!Jw:_id
ul Ш.k i!l МШ!t
Войнаимир Толстой
2 2
2 Дубровский 2 Пушкин
3 3
3 12 стульев 3 И.�rьф
3 4
4 Золотой 4 Петров
4 3
те.�rевок
4 4
Как можно видеть из данного рисунка, книги «Война и мир» и «Дубровский» имеют по
одному автору (Толстой и Пушкин). А вот следующие две книги «12 стульев» и «Золо
той теленок» - имеют двух авторов (Ильф и Петров). Записи в таблицах вооk и Author
не повторяются - они уникальны и существуют в единственном числе (в начале ли
нии, показывающей связь, стоит 1). А вот в связывающей их таблице book_author может
быть как множество книг, так и множество авторов (на конце линии связи стоит знак
бесконечности). В таком случае таблицы вооk и Author являются главными и равнознач
ными, а book_author - связующей таблицей, которая содержит только индексы связан
ных записей из главных таблиц.
Вот теперь, с учетом рассмотренных связей, можно приступить к созданию таблицы
для самих книг. В ней мы будем хранить всю информацию о книгах (название книги,
жанр, язык, автор и т. п.), но не о конкретных (физических) экземплярах книг. Каждый
экземпляр книги может находиться в различных состояниях, и для этого будет создана
отдельная модель (таблица в БД).
Пример создания веб-сайта на Django 385
# книги
class Book(models.Model):
title = models.CharField(max_length=200,
help_tехt="Введите название книги",
verbose_name="Haзвaниe книги")
genre = models.ForeignКey('Genre',
on_delete=models.CASCADE,
help_text=" Выберите жанр для книги",
verbose_nаmе="Жанр книги", null=Тrue)
language = models.ForeignKey('Language' ,
on_delete=models.CASCADE,
help_tехt="Выберите язык книги",
verbose_name="Язык книги", null=Тrue)
puЬlisher models.ForeignKey('PuЬlisher',
on_delete=models.CASCADE,
help_tехt="Выберите издательство 1',
vеrЬоsе_nаmе="Издательство", null=True)
year = models.CharField(max_length=4,
hеlр_tехt="Введите год издания",
verbose_nаmе="Год издания")
author = models.ManyТoManyField('Author',
hеlр_tехt="Выберите автора (авторов)
книги",
verbose_name="Aвтop (авторы) книги")
summary = models.TextField(max_length=lOOO,
hеlр_tехt="Введите краткое описание книги",
vеrЬоsе_nаmе="Аннотация книги")
isbn = models.CharField(max_length=lЗ,
hеlр_tехt="Должно содержать 13 символов",
verbose_name="ISBN книги")
price = models.Decima1Field(decimal_places=2, max_digits= 7,
hеlр_tехt="Введите цену книги",
verbose_name="Цeнa (руб.)")
386 Глава 9
В приведенной модели все поля имеют поясняющий текст (help_text) и удобно читае
мое имя (verbose_name).
Для названия книги создано поле title - это текстовое поле типа CharField. На назва
ние книги наложено ограничение 200 символов.
Для хранения информации о жанре книги создано поле genre, которое по первичному
ключу связано с моделью Genre. Это поле допускает наличие пустого значения.
Для хранения информации о языке, на котором написана книга, создано поле language,
которое по первичному ключу связано с моделью Language. Это поле допускает наличие
пустого значения.
Для хранения информации об издательстве, которое выпустило книгу, создано поле
puЬlisher, которое по первичному ключу связано с моделью PuЫisher. Это поле допус
кает наличие пустого значения.
Для хранения информации о годе издания книги создано поле year, это текстовое поле
типа CharField. На год издания книги наложено ограничение - 200 символов. Это поле
допускает наличие пустого значения.
Для хранения информации об авторе (авторах) книги создано поле author, которое по
первичному ключу связано с моделью Author.
Для хранения аннотации книги создано поле surrmary - это текстовое поле типа
CharField. На аннотацию книги наложено ограничение - 1 ООО символов.
Для хранения уникального международного номера книги создано поле isbn - это тек
стовое поле типа CharField. На уникальный номер книги наложено ограничение -
13 символов.
Для стоимости книги создано поле price - это числовое поле типа oecimalField. На
стоимость книги наложено ограничение - два знака после запятой.
В модели имеется поле photo для ввода изображения обложки книги (типа ImageField).
Поле photo имеет атрибут upload_to='images'. Это означает, что ·все файлы с изображе
ниями обложек книг будут автоматически сохраняться в папку проекта с именем images.
В данной модели определено несколько методов.
Метод_str_() вернет наименование книги.
Метод get_aЬsolute_url() вернет URL-aдpec, который можно использовать для доступа
к детальным записям для этой модели. Например, на странице пользователю выдана
строка с названием книги, которое подсвечивается как ссьmка на другую страницу.
Пример создания веб-сайта на Django 387
--
ВooklashJК:1! (Эt.-ИIOl."IIIJ)W)
Sfatus (Cra,:yc)
�-id mtш.Jd
Вооk(Ка■rа) id
1d tМ1е. 1
Нас:�шаде
Войнаныир 2 B3Ul3c
1 2
2 Дуброаавй 3 Продав
2 3
2 3
2 3
Рис. 9.25. Связи между книгами, экземплярами книг и статусом каждого экземпляра
Как видно из рис. 9.25, в базе данных интернет-магазина имеется информация о трех
экземплярах книги «Война и мир» и трех экземпляра книги «Дубровский». При этом
два экземпляра книги «Война и мир» находятся на складе, а один экземпляр заказан
покупателем, но еще не продан. Все три экземпляра книги «Дубровский» проданы.
Таблицы вооk и status содержат всего по одной записи об объекте, а в таблице
Bookinstanceимеется как множество записей о самих объектах (книгах), так и множество
записей об их состоянии (статусе). Таким образом, мы имеем дело со связями «один
ко многим». Модель для книг вооk у нас уже есть, значит, нам нужно создать еще две
модели: Status и Bookinstance. Начнем с модели Status (листинг 9.14 ).
388 Глава 9
Как можно видеть из листинга 9.14, модель status содержит одно текстовое поле (типа
charFielct), которое назьmается name. Это поле будет использоваться для описания стату
са книги - оно ограничено 20 символами и имеет текст подсказки: help_text. В качест
ве удобно читаемого имени (verbose_name) указано значение "Статус экземпляра книги",
поэтому именно оно будет выводиться на экран в формах рядом с полем name. В конце
модели объявлен метод _str_(), возвращающий значение статуса экземпляра книги,
которое будет внесено в конкретную запись.
Теперь можно перейти к созданию модели вookinstance (листинг 9.15).
# экземпляр книги
class Bookinstance(models.Model):
book = models.ForeignKey('Book',
on_delete=models.CASCADE, null=True)
inv_nom = models.CharField(
max_length=20,
null=True,
hеlр_tехt="Введите инвентарный номер экземпляра",
verbose_name="Инвентарный номер")
status = пюdels.ForeignKey('Status',
on_delete=пюdels.CASCADE,
null=True,
hеlр_tехt='Изменить состояние экземпляра',
verbose_name="Cтaтyc экземпляра книги")
due_back = models.DateField(null=Тrue,
Ыank=Тrue,
hеlр_tехt="Введите конец срока статуса",
verbose_name="Дaтa окончания статуса")
# Метаданные
class Meta:
ordering = ["due_back"]
def str (self) :
return '%s %s %s' % (self.inv_nom, self.book, self.status)
Для названия книги создано поле ьооk, значение для него будет подгружено из модели
вооk, с которой имеется связь по первичному ключу.
Для задания статуса экземпляра книги (на складе, в заказе, продана и пр.) предусмотре
но поле status, значение для него будет подгружено из модели Status, с которой имеется
связь по первичному ключу.
Пример создания веб-сайта на Django 389
Для задания даты окончания действия статуса для экземпляра книги (например, даты
окончания действия заказа) создано поле ctue_back- это поле для ввода дат типа
DateField.
Для сортировки экземпляров книг создан класс меtа, при этом все экземпляры будут
отсортированы по дате окоцчания действия статуса.
Метод _str_ () представляет объект Bookinstance, который будет выводить содержимое
нескольких полей: название книги, ее инвентарный номер и статус.
Будем считать, что весь приведенный здесь код внесен в файл models.py, расположенный
по пути: World_books\WebBooks\catalog\models.py.
Таким образом, на этом этапе все модели созданы, и можно приступить к миграции
данных. Как было отмечено в предыдущей главе, миграция выполняется в два этапа. На
первом этапе с помощью менеджера Django формируется программный код, который
будет создавать таблицы в БД. Для этого в окне терминала PyChann выполните команду
python manage.py makemigrations
В результате будет создан файл миграции: Wor1d_books\WebBooks\catalog\migrations\0001_initial.py
и получено следующее сообщение (рис. 9.26).
Тern,inal: Local +
Term,nal: Local +
.::.ppl:,. all 1тig,·,ations: admin, autf1" catalog 1 conteпttypes 1 ::_.e�:_,ic:пs
Running migrations:
дpplying coпtenttypes.0001_initial ... ОК
..:..polyi.ng autfi.0001 initial... ОК
дpplyiпg a,J,r,in.0001 initial... ОК
:.pplying a,jmin.OOIЭ2_logentry_remove_auto_add ... ОК
Аррl'/ irч, admin.GООЗ_logentry_add__ actiоп_flag_cl1oices. .. ОК
,\pplyiпg contenttypes .0002_гemo,;e_content_type_name... ОК
.:.ррlуing a1Jtl1, 1}002_alter_permi s sion_name_max_lengtl1... ОК
�pplу ing a1Jt 11.&003_alter_1Jser_email_max_length... ОК
.:.pplyiпg .,utl1.\}13{14_altег _1Jс,ег_useгname_opts... ОК
,;::.pt.1 1·/iпt� a ..11:f1.0005_alteг_u:ol:'t·_last_login_nLJll ... ОК
1
дpplying autl1.00f16_requiгe_contenttypes_0002... ОК
4pplying a1Jtl1. 0007_alteг_'Jalidatoгs_add_error_messages... Ok
.:с.ррlуi пg a1Jt11.0(+08_ а ltег_ u .er _useгname_max_lengtl1... ОК
0
.:.�•pl::;ing autl1.0М19_alter-"_user_last_пame_max_lengtt1... ОК
;;ppljiпg a,Jtl1.0010_alteг_group_пame_max_lengtl1... <Ж
..\pplying autf1.0011_update_proxy_permissions... ОК
. .::..ppl/inga1Jtf1. 0012_alteг_11sег_fir-st_пame_max___lengtf1 ... Ok
Applyiпg catalog.000l_iпitial... ОК
.::..pplyiпg .:-e.:::..:::.icn:,.0001 initial... ОК
Рис. 9.27. Создание таблиц в БД на основе миграции для сайта «Мир книг»
Tools Help ,,
Структура ОграttИЧЕt14Я
Рис. 9.28. Таблицы в БД, созданные на основе миграции для сайта «Мир книг»
Пример создания веб-сайта на Django 391
from .models import Author, Book, Genre, Language, PuЬlisher, Status, Bookinstance
admin.site.register(Author)
392 Глава 9
admin.site.register(Book)
admin.site.register(Genre)
admin.site.register(Language)
admin.site.register(PuЬlisher)
admin.site.register(Status)
admin.site.register(Bookinstance)
Этот код просто импортирует созданные нами модели, а затем в нескольких строках
admin.site.register(<имя модели>)
После ввода этой команды Djaпgo автоматически сформирует имя пользователя (по
умолчанию это имя компьютера). Можно оставить предложенное имя и нажать клави
шу <Enter>, а можно набрать другое имя суперпользователя и подтвердить его также
нажатием клавиши <Enter>.
Затем вам будет предложено ввести электронный адрес суперпользователя и дважды
ввести пароль для входа суперпользователя в административную панель. Если введен
ный вами пароль не удовлетворит требованиям системы (слишком простой, слишком
короткий и пр.), будет выдано соответствующее предупреждение. После проверки
валидности пароля нужно будет нажать клавишу <У>, после чего вы получите сообще
ние, что суперпользователь успешно создан (рис. 9.30).
Пример создания веб-сайта на Django 393
Рис. 9.30. Соэдание суперпользователя сайта «Мир книг» в окне терминала PyCharm
Администрирование Django
Имя пользователя:
anatoly
Пароnь:
0 Адм•ни.::триро.,,ни• cam I Ад Х + у
f- ➔ С ф 127.0.0.1:8000/admin/
� АвиабW!еты О Яндею:: - Пер,весrи G Gmail
Администрирование сайта
CATALOG
Последние действия
Authors +дооави,ъ ; И3менить
НеДОСl)IПНО
8ooks +доба311ТЬ ; Изменить
PuЫishers +добавкть
,.
,; И.�МfЖИТЬ
ПОЛ"30ВАТЕЛИ И ГРУППЫ
1 Sыбра1«1 О обwкто• иа 7
о GENAE
о У'186на11
о наr--
о Фамтасrика
----·--�-·
о Г1ро3а
о Прмкп-1111
о По83111111
о Дm1кт18ы
7genres
Рис. 9.33. Окно администратора сайта после ввода семи жанров книг
Администрирование сайта
CATALOG
Последние действия
Authors + Доба11кть ,tf И3менить
+ Научно-техническая
Gan"
Languages + Доба11ить , И3менкть + Фантастика
Genr,
PuЫishers + Про:,а
Gen,-
statuss + Добаl!ИТЬ ,f И,менить
+ Приключения
Genп,
ПОЛЬЗОВАТЕЛИ И ГРУППЫ
+ Пrезия
Ganre
Груnnы + ДО6а11ить , И:1менить
Добавить author
Имяа11тора:
Введите нм:я аатора
ляев
Фамилия а1Пора: l�
Вв:едите фамилию автора
Сllедения о6 а11торе:
� - -
- - - -
- - - ·····
- ...,. .,.,...,..............,...,...,...,.,,..., .....,.,.........- -
! Алекс;�ндµ Романович Беляев (16 марта 1884, Смоленск, Смоленская губерния). Русский и
: советский писатель-фантаст, репортер и адвокат, журналист. Один из основоположников
: советской научн<rфантастической литературы, первый из советских писателей, целиком
: посвятивший себя зтому жанру.
Среди наиболее известных его романов: «Голова профессора L\O;.IЗЛSJ•, •ЧеЛО8еК•амфибия•,
с:Аризль•, «Заезда� и многие дРУmе (!!Сего более 70 научн<rфантасn1ческих произведений, в
: том числе 17 романов). За значительный вклад в русскую фантасmку и провидческие идеи
� назыаа.ют «русским� Верном..
8f!еАкте--<:ведения- об а вторе
В этом окне для ввода дат будет автоматически подключаться календарь. Дату можно
либо выбрать из календаря, либо ввести с клавиатуры. Если при ручном вводе даты
будет сделана ошибка, то Django выдаст соответствующее предупреждение. Поле для
ввода сведений об авторах имеет достаточно большой размер, кроме того, его можно
расширить (сузить), зацепив мышью и переместив метку в правом нижнем углу поля.
Сформировав базовые. справочники, можно перейти к заполнению данными связанных
с ними таблиц. Введем в базу данных несколько книг. Для этого щелкнем левой кноп-
Пример создания веб-сайта на Django 397
О books
Рис. 9.36. Начальное окно администратора сайта для добавления новой книги
кой мыши на ссылке Добавить рядом с моделью Books - откроется следующее окно
(рис. 9.36).
В этом окне видно, что на текущий момент в БД нет ни одной книги, но при этом при
сутствует кнопка ДОБАВИТЬ ВООК +, позволяющая войти в режим ввода сведений
о книгах. После нажатия на эту кнопку будет открыто основное окно для ввода сведе
ний о книгах (рис. 9.37).
Вспомним, что модель «Книги» связана связью «один ко многим» со следующими мо
делями:
□ «Жанр книги»;
□ «Язык книги»;
□ «Издательство».
Следовательно, один жанр - много книг, один язык - много книг, одно издательст
во - много книг. В связи с этим для выбора жанра, языка и издательства Django созда
ет поле выбора в виде вьшадающего списка. А вот книги и авторы имеют связь «многие
ко многим». Поэтому для выбора автора (авторов) книги предназначено по_ле в виде
простого списка, в котором можно одновременно выбрать несколько авторов. Рядом
с этим полем имеется подсказка - для выбора нескольких авторов необходимо щелк
нуть в списке на фамилии автора, удерживая при этом нажатой клавишу <Ctrl>.
Рядом с полями ввода жанра книги, языка и автора книги имеется значок ЕЕ!. Если
щелкнуть по нему левой кнопкой мыши, то появится новое окно, в котором можно по
полнить соответствующий справочник.
Введем в этом окне хотя бы по одной книге каждого автора. А для Ильфа и Петрова
введем две книги, чтобы проверить, как будет работать связь между таблицами «мно
гие ко многим». Результаты ввода сведений о книгах показаны на рис. 9.38.
Если щелкнуть мышью на названии книги, то будет показано окно с полной информа
цией об этой книге (рис. 9.39).
398 Глава 9
�Добавить Ьооk
+
•
......,.. ___ y_....ь.--.ri-·eornmo,,cr .......� ....
...е,р..._-,,.
AНNcrrlцllll IOWIC
18N-
......,. ____
---�-
�--- lllwlllpll8фllnlФll\nи.lllll6pltl
Рис. 9.37. Основное окно администратора сайта для добавления информации о книгах
Дeiicraмe:\�-==-------v_,I ВЫnмм11>
в..6ро,.оо-.. s
о 11ООК
о �ll02Дy0
Рис. 9.38. Окно администратора
сайта с добавленной
о � информацией о пяти книгах
о ВОiiнаМ181р
о Эoмroii-
о 12c:tyll....
SЬoolcs
Пример создания веб-сайта на Django 399
Изменить Ьооk
••+-
Allthota +дшамт.
i S<»iHOll""1P
С.-• + д*•�n.
Lilfl!IU\'lc;/4!1 + д<>&•�"'
�--
РuЫ..... +д<>б.1><n
$wuss +�...... i llмtl>« ·--]
v � + •
1
� А8Тс!р '""'""
A,,ttoTAЦlllf -;
ISВHk- 978,6,389-062
�-,з.;;;;;;..
__,,_,_,.
2500,00
И�,цнме�"' н.----�
- е Фоiм,•""'•"
е-,,,,,��
Добавить status
Статус экземпляра
книги:
Рис. 9.40. Окно администратора сайта для ввода информации о статусе экземпляров книг
Дейсп1ие. v Выполнить
ВыбраkО О oow,m,a µ3 З
0 SТAТUS
О Продана
О Вза каэе
О Наскладе
З statuss
Здесь можно задать пар<;1метры для каждого отдельного экземпляра книги (инвентар
ный номер) и указать статус этого экземпляра. Для тестирования нашего приложения
введем информацию о нескольких экземплярах каждой книги. Результаты ввода дан
ных об экземплярах книг представлены на рис. 9.43.
Итак, мы заполнили информацией все наши модели, а вернее, соответствующие табли
цы в БД. Мы можем убедиться в том, что информация действительно записана в Бд,
если откроем содержимое таблиц БД с помощью менеджера SQLiteStudio (рис. 9.44).
Таким образом, используя административную панель, мы смогли заполнить таблицы
БД информацией через веб-интерфейс, при этом, не создав ни одной НТМL-страницы,
и не прибегая к SQL-запросам. Весь необходимый интерфейс бьm нам предоставлен
внутренней структурой Django. И это еще не все - в Django имеется возможность из
менить настройки и внешний вид этого интерфейса, а как это делается, описано в сле
дующем разделе.
Пример создания веб-сайта на Django 401
Вооk:
инвентарным номер:
Статус эоеммяра
мнwм: [-vj
Изм.житъ состо�:.н� жземnnАра
Рис. 9.42. Окно администратора сайта для ввода информации об экземплярах книг
Действие: �
! ===----------__," i [
Вwбр,но О o6ъetm>• из 9
выполнить J
о 800КINSТАМСЕ
о 1 Дубровский На скnаде
о 23о/lотом-В 331G1:м
о 2 Дубровский В заказе
9 ЬООk instances
Рис. 9.43. Окно администратора сайта после ввода информации об экземплярах книг
402 Глава 9
re Vie,v Tools
Da.
� ,1 с1, {SQUte3J
,. JI ct,Q {SQUt• 3)
first r,ame 1.>st n•= date of Ьir aЬout
4 lroi
Табл�ц. (1В) photo-====-1
� �aulh_group Алекса.ндр. Бv�яее : 1882-03-16 j Александр Ромаttоеич Беnяее (16 марта , Беляев_А,jрg
'1884, Смоленск, Смол енская губерния). i
aulh_group_pernjs...
� l)!j 1
...!.. .............. . ··· ··•·-··-···-l--"У�-����--�--����ский nисат .. __J
� �aulh� Aneкai,w,/ty.:;_;к�н '1799-05-26: · Александр Сергеевич Пушкиtt (26 мая , Пушкиtt_А.jрg
� �aulh_user 1799, Москва) - русский nо;,т, драматург'
� ifl aulh_user_goups м про3аМК. УЛОЖИ!IШИЙ осн !
� aulh_user_user_ре ... Толстой 182&-08-28: Лее Нкколаееич Толстой {28 авrуста Толст�i(Л:j"рg '
� thor 3 1828, Яская Поляка, Тул ьская rуберния). 1
t, _ ,t\_�_':f__�_.f:!��Оt>л.��-.�3в�ны___
:9 J
= """"
catalog_Ьook
� �: ca...___Ьook_auttюr 4 Иль
я 111:,;�Ф :iз91:10--оз,
Илья дрнольд�вич ��Ф (при рождении [111:,;ьф_lllJpg
4 j ! Иехие.r,-Лейб Арьевич Фа йtGил.ьберr; З !
�ca _ · о==ктября 18 7 го есс а)
� talog Ьookinstana, III-''-- ...,��-+�--'--,-
-5 j Евгений ! Пnро1 �-,..,...;-!
9 да, Од , i
l> Jm
cataioQ_oenre 11902-10-30 ! Евгений Петрович Петров (настоящая---;-JП- _р_оа_Е.jрg
� �catalog_�
ет
: фамилИR - Катаев; 30 ttоября 1902).
�m
5
ca j Русский советский писатель, сц
talog_pul,isher
9. 7. Изменение конфигурации
административной панели Django
Административная панель Django обеспечивает эффективную работу с БД разработчи
кам сайтов, используя информацию из зарегистрированных моделей данных:
□ каждая модель имеет набор записей в виде строк, создаваемых методом _str_()
модели, и связанных с представлением (view) для их редактирования. По умолчанию
в верхней части этого представления находится меню действий, которое позволяет
удалить несколько записей за раз;
□ формы для редактирования и добавления записей содержат все поля модели, кото-
рые расположены вертикально в порядке их объявления в модели.
Однако для упрощения работы с административной панелью можно настроить интер
фейс пользователя. Вот некоторые доступные настройки:
□ List views (список представлений):
• добавление дополнительных отображаемых полей или информации для каждой
записи;
• добавление фильтров для отбора записей по разным критериям (например, статус
выдачи книги);
• добавление дополнительных вариантов выбора в меню действий и места распо
ложения этого меню на форме.
□ Detail views (подробное представление):
• выбор отображаемых полей, их порядка, группирования и т. д.;
• добавление связанных полей к записи (например, возможности добавления и
редактирования записей книг при создании записи автора).
Пример создания веб-сайта на Django 403
В этом разделе как раз будут рассмотрены некоторые желательные изменения для со
вершенствования интерфейса пользователя нашего сайта «Мир книг». В частности,
включение дополнительной информации в списки моделей вооk и Author, а также улуч
шение расположения элементов соответствующих представлений редактирования.
□ Созданы новые классы вооk и Bookinstance. В этот раз для создания и регистрации
новых моделей мы воспользовались декоратором @register (он делает то же самое,
что и метод admin.site.register()):
# Регистрируем класс BookAdmin дпя книг
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
pass
# Регистрируем класс BookinstanceAdmin дnя экземnляров книг
@admin.register(Bookinstance)
class BookinstanceAdmin(admin .ModelAdmin):
pass
Пока что все наши admin-клaccы пустые (содержат только инструкцию pass), поэтому
в интерфейсе панели администратора сайта ничего не изменится. Добавим код для за
дания особенностей интерфейса моделей.
5 authors
Рис. 9.45. Сведения об авторах, показанные в виде таблицы с помощью кортежа list_display
Эту функцию необходимо вставить в модель вооk в файле models.py так, как показано на
рис. 9.46.
В этой функции организован цикл с инструкцией for. В теле цикла выбираются все
авторы, связанные с данной книгой, из них формируется список, который будет воз
вращен в точку вызова. Для этого списка формируется короткое имя «Авторы»:
display_author.short_description = 'Авторы'
Теперь необходимо заменить класс BookAdmin в файле WebBooks\catalog\admin.py на версию,
приведенную в листинге 9.20.
406 Глава 9
► 11 media
► 811 WebBooks
:: t ' • ,, � 1 < ,1..,,1, • р• ,' < 1,1 ( 1\ ,, 1f i ;�
i f d1splay_authoг( )·
f, db.sqliteЗ
· Jn1n([zн1thor.lac;,t_name -f authoг d,Jtf1nr all()])
i'- m,,nage.py
► 11111 frti:-roal L1braпe,;:
d1splay_.:iuthor.shurt_de5cг1pt1on � •.,.
f1"'0 ')crдtches .эnd Con�ole�
j:
. title
CATAI.OG
Выберите book для изменения ♦+i!Фiiii+ii=-
Authors +добавить Действие: V, Выполнить
SЬooks
Рис. 9.47. Развернутый список книг на основе модернизированной модели данных вооk
Пример создания веб-сайта на Django 407
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'genre', 'language', 'display_author')
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'genre', 'language', 'display_author')
list_filter = ( 'genre', 'author')
@admin.register(Bookinstance)
class BookinstanceAdmin(admin.ModelAdmin):
list_ filter = ( 'book', 'status')
ФИЛЬТР
Действие: V
О 2 Зоnсmж - в :�аказе
о 112стуnьеD на складе
Продана
о 2 Дубровский В :,ака:,е
9 ЬОоk instances
Действие: �r -_-_-________
v i lВыполнить i
Выбраж, О объектов .,. 5
о Евrенмй Петров
о Иnья Ильф
о Лев Толстой
о Аnексаwдр Пушкин
о Александр Беляев
Sautho!s
Теперь щелкнем мышью на фамилии одного из авторов, например Петров. После этого
появится страница с детальной информацией об этом авторе (все поля из cпиcкa
fields). При этом поля будут расположены так, как они приведены в атрибуте fields
(рис. 9.52).
Изменить author
Петроа
EiiSH!k♦
Фамм1111аатора: [ Петров
-- - - -
В•е,дl'П• ф1мми�0 •sюp;i
ИмАавтора: , fаrений
Для изменения списка отображаемых полей также можно использовать атрибут exclude,
который позволяет исключить часть полей модели из отображения в форме, при этом
все остальные поля модели будут отображаться в форме.
Пример создания веб-сайта на Django 411
ФИЛЬТР
ДеЙСТ!lие: ! -- vj
А. Ьооk
Все
0 IIOCЖINSТA.NCE 12 стуnьее
Эоll(!ТОЙ теленок
О 1 ДубровскмйНа скnаде
Война и мир
О 2 Война и мир ПрQqана ДубJЮIIСКМЙ
Продавец 603духЭ
О 1 Война и мирНа скnаде
0 2 Зon011:lii Пllllt!OК8 --
А. Статус экземпляра
книrи
0 1 Золотой теленок на CIUNW!
Все
О 3 12 c,ynbl\8На сжnаде Наскnаде
83ака:,е
0 2 12 Сl)'Лье&На скnаде Продана
О 112.стульевНаскnаде
О 2 Дубровский В заказе
9 book instances
Book: Дубровский V
Инвентарный номер: 2
-
статуса:
, ..... · ·· · .. ,. P❖ik'=Фii
.. .
Сохранить II npoДQml(ИtЬ ред-акn,роаание
class Booksinstanceinline(admin.TaЬularinline):
model = Bookinstance
# admin.site.register(Book)
# Регистрируем класс BookAdmin мя книг
@admin.register(Book)
class BookAdmin(admin.ModelAdmin):
list_display = ('title', 'genre', 'language', 'display_author')
list_filter = ( 'genre', 'author' )
inlines = [Booksinstanceinline]
Теперь на этой форме щелкнем мышью на одной из книг. В результате откроется новое
окно с подробными сведениями о выбранной книге, а также будут показаны связанные
записи со сведениями обо всех экземплярах этой книги. Поскольку форма достаточно
большая, то продемонстрируем ее содержание в виде двух рисунков. На рис. 9.57 пока
зана верхняя часть формы, где мы можем видеть и редактировать всю информацию
о выбранной книге.
А на рис. 9.58 показана нижняя часть формы, где мы можем добавлять и изменять све
дения об экземплярах этой книги.
Применительно к этой странице разработчики Django реализовали функциональный
и достаточно удобный интерфейс для разработчиков сайтов. Здесь можно одновременно
414 Глава 9
-- -- --
Дейсп,ме: (- v) 8и1оJ»мть ВЫС!раноО
о6ьекТоD .., 5 �ж.жр .........
о --IOtlll'II В<;е
ДетекrмDы
о ПродаlИ!Ц IIO>A,xa Фантастика Русс:1<11й Бепяее """"""
о Дy6polleioui Про:,а P)'Cclool Пу\ul<МН
Приои,�оченмя
Про3а
о Soiltaи ""Р Про,а Русский Toncтoli Фантастика
Нlll"'НО-Тt!•нм.......,.
о Зonorot'i- ilpl4КЛIOЧfНllfl Русский ИЛЬФ, Петроо у-
о 12cry- Прмои,юченмя Русский ИЛьф, ПетроD
SЬOOks �датаркниги
Все
вомнаиммр
�------�
/ПРо38
вwis.p.m. •анр д,,111 кнwм
vJ,+•
[ __
Руtск
__и_й__.,...,] #" +•
[ 1985
•война и мир' Л. Н. Toncтoro - книга на есе еремена. Как будто она сущест11Ооала
1
Аннаr- fOtllnf,
осеrда. насrолько :11<аКОNым кажется текст, едоа мь, открыD&ем nереые стренмцы
романа, настолько памятны мноrие ero :юиiЮДЫ: oxara и СDIПКИ, nереый бал Наташи
1'осrо!1оЙ, лунная ночь D Отрадном, КН113Ь АндРей е сражении при Дус!ерnице...
Сцены •ммрной•, ceNeйнoil ЖИ3НИ
�ами ИМ8ЮШМ.NН 3нацение дОА хоаа DъR:Й..М11JИOO,ш,OO..,йo.ИCТ1!1CtlIOA1rllUЯUIUIII.-'""
!
В� ,i:pпw.are оnисанме мкмrм
Цена (ру6.):
Рис. 9.57. Верхняя часть формы для ввода и редактирования информации о книге
Пример создания веб-сайта на Django 415
2 Сеrодняl� о
Sнкuажtе: Bawe-лок.ал� 8РеА111 o�•iiт m-ар.,А80! -еереера м• Э
ч�•.
V
----� Сеrодняl�
8нж.4анме: Заwе-покальное 11p-et.1R о"ТСrйт от вре-мl!Юt серв,ер• на З
часа.
1 Сеrодня l i!i11
о
Сеrодня1m о
Sн131ани.t: B&IJ.lf- lli!Жarn.мoe ар� о�от �:м..нм a!JIИ$1• на З
цаса.
ие экземпляра
' Сегодня l di!I
Рис. 9.59. Фрагмент нижней части формы
для ввода и редактирования информации об экземплярах книг с подсказкой
Изменить book
Война и мир
�к:тироаать
Ha311attмelOIМПI: ! Война и мир CПIJIIIIOЧHИIIМ
я,ыккнигм: ! Русский
� - -
-�
"'i ;- + ф
8ы:6Ер1П1! ЯЗЫК kНИf'И
И:,дательсТIIО: [ литРес
vj ; + ..,
�------'
Выберmi! ·Изда"П:!ЛЬСТИО
i Сегодня 111 19 20 21 22 23 24 25
i
i
Внf.tМанк,е: Вё!wе-JЮк.аnьное вреwя с
26 27 28 29 - 31
часа. _
Вчера I Сегодня I Завтра
! Ceroдняll!J Отмена
Здесь в первой строке задан URL-aдpec, во второй строке путь к папке media, в которой
будут храниться файлы пользователей.
В самих моделях Author и Book для хранения изображений было создано поле photo
типа ImageField, а также указана папка, в которой будут сохранены загруженные изо
бражения (images).
Если посмотреть на структуру базы данных, то можно увидеть, что поле типа ImageFielct
на уровне БД представлено полем типа varchar (рис. 9.62).
�
Фильтр ло ,1мени Е1 r.,
1
1> 1 dЬ (5Qlite3)
Имя таблиць1: cata��_,.au
_. /11
т;
dЬО (SQlit• 3}
_. � Таблиul,1 (18) Первичный
Имя Тиn данных
6 ключ
m
t> auth_group - -1
m
1> auth_group _permissions 1 id _} �_ nt er
1> auth_permission 2 first_name varchar (НЮ)
t> [1m] auth_user [ 1
3 1.ast_name ; varchar (100)
1> ID1J auth_user_groups
t> 1m] auth_user _user_permissions 4 date_of_birth date
1> i catalog_author 5 about text
""
1> � catalog_';::boo::;:-k----,t-,б-h p o-to-� varchar (100)
1> !lmJcatalog_Ьook_author
Поле varchar предназначено для хранения строковых данных переменной длины (по
умолчанию задано максимально допустимое число символов 100). Фактически .здесь
хранятся только имена загруженных файлов. Сами же файлы с изображениями будут
сохранены в папке media/images (рис. 9.63).
Таким образом, в базе данных бьmи записаны только имена загруженных файлов, а
сами файлы фактически помещены в папку проекта media/images. Теперь посмотрим, как
можно реализовать показ загруженных изображений в формах административной па
нели.
В административной панели по умолчанию отображаются все поля модели данных. Но
при желании можно не только изменить порядок отображения существующих полей,
но и добавить новые поля, которых не было в модели, и поясняющие надписи к этим
полям. Воспользуемся такой возможностью для того, чтобы в формах административ
ной панели показать загруженные изображения. Новое поле создается в модуле
catalog/admin.py простым добавлением нового метода к классу с описанием модели.
418 Глава 9
В первой строке выполнен импорт функции Django foпnat_html. Она нужна для того,
чтобы отформатировать и показать изображение на НТМL-странице. Затем в списке
отображаемых полей list _display добавлено новое поле 'show_photo'. Так как этого
поля нет в модели, то мы вносим его в список поле с признаком «только для чтения»
с использованием инструкции:
readonly_fields = [ "show__photo"]
Пример создания веб-сайта на Django 419
После этого создаем функцию (метод) с именем show photo () . Этот метод в параметр
obj принимает зарегистрированную модель с авторами книг, а затем через функцию
format_html () возвращает ссьшку на изображение { obj . photo. url}, а также с по
мощью стилей задает максимальную высоту изображения в 100 рх. В последней строке
создана поясняющая надпись к этому полю-«Фото».
Еще один вариант вывода изображений в административной панели предостщшяет
функция mark safe. В листинге 9.25 в закомментированных строках показан этот ва
риант:
# from django.utils.safestring irrport mark_safe
# можно и с использованием функции mark_safe
# return mark_safe(
# f'<img src="{obj.photo.url}" style="max-height: lOOpx;">')
Затем вносим аналогичные изменения в класс вookAdmin (листинг 9.26, изменения выде
лены серьiм фоном).
return format h
f'<m,..src=" 0151 -' RJioto.url}"
how hoto.short descri tion = 'Об.ложка'
urlpatterns = [
path(' ', views.index, name='index'} ,
path('admin/ ', admin.site.ur 1s) ,
420 Глава 9
if settings.DEBUG:
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL,
document_root=settings.МEDIA�)
Languages + Добавить
PuЬlishers +добав�ть
Группы +добавить
0 Лев Толстой ToncтoйJl.jpg
Пользователи +добавить
Рис. 9.64. Новое поле в административной панели для показа загруженных фото авторов книг
Как видно из данного рисунка, в списке отображаемых полей появилось новое поле
Фото, в котором показаны загруженные изображения авторов книг. Обратите внима
ние, что поле Фото автора, в котором показано имя загруженного файла, тоже пред
ставляет собой ссылку. Если щелкнуть мышью по данной ссьmке, то будет показана
отдельная страница с загруженным изображением (рис. 9.65).
Пример создания веб-сайта на Django 421
0 х +
*
Пушкин_А.Jрg (218•288) V
� ➔ С ф 127.0.0.1:8000/media/... <а. !В □ �
':"� Аsиабклеты О Яндек:с Q.r Перевес� G Gmai]
Действие: v Выrюлнить
объектов из 5
! Автор ЮiИГИ
Все
Беляев
О Boiillaимиp Проза Русский Толстшi
Пушкин
Толстой
ИлЬФ
Петров
Рис. 9.66. Новое поле в административной панели для показа загруженных фото обложек книг
422 Глава 9
Эта страница будет достаточно простой, на ней мы покажем количество записей в каж
дой модели и боковую навигационную панель со ссылками на другие страницы сайта
(главное меню). В результате мы приобретем практический навык написания простых
URL-преобразований, получения записей из базы данных, применения шаблонов для
вьmода данных из БД.
Вернемся к структуре приложений, написанных на Django (рис. 10.1 ).
..
- - - - - - .,.- - - - ---,,,,
, НапрзвВ'IЬ 1~-_
1 запрос в View _ 1 Форм.нрование 1
1
"- -- 1 ответа
... _____ ..... ... ... ,;;·"
1 1
,- .
1 Запись -чтевве :
' View _,....,., ...
1
------
Ш1ННЬ1Х
- ... 1
(•,;ews.py)
1 I
+ .,,..-------- '
·+
1 J
1 J Загрузка 1
_ .... -=.-:. ·:::.:.:::
--------�
1 t
шаблона
- ·-- "
1
l J+э,,,
r
1I
-�
Model Шаблоны
DB (models.py) (fi.lename.html)
Рис. 10.2. Создание URL-преобразования для перехода на главную страницу сайта «Мир книг»
urlpatterns = [
path (", views. index, narne='index') ,
Здесь функция path() определяет URL-шаблон (в нашем случае это пустая строка в апо
строфах), функцию отображения главной страницы сайта (views. index) и уникальное
имя для функции отображения (narne='index'). Теперь если в запросе, поступившем от
внешнего пользователя, присутствует пустая строка, то этот запрос будет адресован
к функции index() . В свою очередь, в этой функции будет прописано обращение к БД
для загрузки данных и вызов страницы, которая эти данные вернет пользователю.
В функции path() определен параметр narne, который уникально объявляет, что мы име
ем дело с частным URL-преобразованием. После такого объявления можно использо
вать это имя для «обратного» (reverse) преобразования, т. е. для динамического созда
ния URL-aдpeca, указывающего на определенный ресурс. Например, если мы задали
такое символическое имя, то теперь можно ссьmаться на нашу главную страницу сайта
при помощи создания следующей ссьmки внутри какого-либо НТМL-шаблона:
<а href="{% url 'index' %}">Главная страница</а>
Применение «обратного» URL-преобразования - это достаточно гибкий и эффектив
ный подход для создания ссьmок на различные страницы сайта. В данном случае для
вызова домашней страницы в шаблоне Django достаточно указать ее имя - { % url
'index' %}.
С адресацией главной страницы вопрос решен, теперь нужно создать соответствующее
представление (view).
def index(request):
return HttpResponse("Глaвнaя страница сайта Мир книг!")
Заменим ранее созданные программные строки функции index {) на код листинга 10.3.
В этом модуле сначала вьmолнен импорт функции rencter (выводить, отображать). За
тем созданы две текстовые переменные text_heact и text_bocty, их значения загружены
в объект context, который представляет собой словарь Python. Через функцию rencter
этот словарь передан в ·шаблон НТМL-страницы catalog/index.html. Это пока самый
простой, можно сказать, отладочный код. Нам нужно убедиться, что все URL-aдpeca
действительны, настройки в проекте выполнены правильно и корректно подключились
файлы Bootstrap.
Так как здесь выполняется обрашение к шаблону с именем index.html, то его нужно соз
дать. Для этого в директории templates/catalog/ создадим файл с именем index.html и напи
шем в нем код листинга 10.4.
{% extends "catalog/base.html" %}
{% Ыосk title %}Мир книг{% endЫock title %}
{% Ыосk header %}
<h5>{{ text_head }}</h5>
{% endЬlock header %}
{% Ыосk content%}
<div class="container-fluid my-2">
<div class="row">
<div class="col text-center">
<div>{{ text_body }}</div>
</div>
</div>
</div>
{% endЫock content %}
Это достаточно упрощенный код шаблона главной страницы. В самой первой строке
подключен базовый шаблон (catalog/base.html). Это основной шаблон, который отвечает
за внешний вид всего сайта (он будет создан на следующем шаге). Далее идут блоки,
заключенные в _теги Django. В блоке title выводится текст, который будет виден в окне
браузера в заголовке НТМL-страницы. Далее в блоке header в теге { { text....:head }} будет
вьmодиться текст, переданный из представления view. Этот текст будет находиться
в самой верхней части главной страницы, это, по сути, ее заголовок. Далее следует блок
content - основное содержание страницы. Здесь могут быть таблицы, изображения,
формы и т. п. Пока мы максимально упростили код этого блока, в котором присут
ствует адаптивный контейнер Bootstrap (class="container-fluid my-2") с одной строкой
(class="row") и встроеной в нее колонкой (class="col text-center"). В этой колонке в теге
{{ text_bocty }} будет вьmеден текст, который передан из представления view.
Поскольку в первой строке подключен базовый шаблон, то его тоже необходимо соз
дать. В папке с шаблонами создаем файл templates/catalog/base.html. В этом шаблоне напи
шем код листинга 10.5.
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 429
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<meta charset="UTF-8">
<rneta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="/static/css/bootstrap.min.css" >
<script defer src="/static/js/bootstrap.bundle.rnin.js"></script>
</head>
<body>
<div class="container-fluid р-1 bg-prirnary text-white text-center">
<div class="row">
<div class="col-2 text-start">
<irng src=" {% static 'irnages/pplOO.jpg' %} " width="70"
height="70">
</div>
<div class="col-10 ">
<hl>Это шапка сайта с логотипом</hl>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="{% url 'index' %}">Главная страница</а>
<а href="{% url 'index' %}">О комnании</а>
<а href="{% url 'index' %}">Контакты</а>
</hб>
</div>
</div>
<div class="container-fluid">
<div class="row text-center text-primary fs-1 fw-bold">
<-div>{% Ыосk header%}
{% endЫock header %}
</div>
</div>
<div class="row text-center text-body">
<div class="col-2 ">
{% Ыосk sidebar %}
<nav class="nav flex-column">
<а class="nav-link" href="{% url 'index' %}">Ссылка 1</а>
<а class="nav-link" href="{% url 'index' %}">Ссылка 2</а>
<а class="nav-link" href="{% url 'index' %}">Ссылка 3</а>
</nav>
{% endЫock sidebar %}
</div>
<div class="col-10" >
<div class="row text-center">
{% Ыосk content%}
{% endЬlock content %}
430 Глава 10
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class= "row bg-primary text-center text-white lh-1">
{% Ыосk footer %}
<р>Это nодвал (footer) всех страниц сайта</р>
{% endЫock footer%}
</div>
</div>
</body>
</html>
рой колонке второй строки находится блок с основным контентом страницы - 1 % Ыосk
content % J, в котором будет выводиться основное содержание страницы сайта.
Заголовок страницы
Боковое
меню
Основное содержание
страницы
Подвал страниць1
Итак, мы создали все базовые элементы для того, чтобы проверить в работе макет соз
данного сайта. Разместим в папке static/images/ файл с изображением логотипа сайта и
запустим наш веб-сервер, выполнив команду
python manage.py runserver
Главная страница сайта будет выглядеть так, как показано на рис. 10.4.
Как видно из данного рисунка, в паре шаблонов base.html и index.html появилось содержи
мое двух текстовых переменных, переданных из представления views. index: «Это заго
ловок главной страницы сайта», «Это содержимое главной страницы сайта».
- - --- - - ---------- - - --- - -
--- --�- - -
--
1
Ссылка 2
Ссылка 3
Это подвал (footer} всех страниц сайта
Рис. 10.4. Внешний вид главной страницы сайта index.html на основе базового шаблона base.html
432 Глава 10
Итак, базовые элементы сайта созданы, теперь можно заниматься модификацией про
граммного кода, созданием новых страниц, улучшая как функциональные возможности
сайта, так и его интерфейс.
def index(request):
text head = 'На нашем сайте вы можете nолучить книги в электронном виде'
# Данные о книгах и их количестве
books = Book.objects.all()
num_books = Book.objects.all().count()
# Данные об экземплярах книг в БД
num_instances = Bookinstance.objects.all().count()
# Доступные книги (статус = 'На складе')
num_instances_availaЫe = Bookinstance.objects.filter(
status_exact=2).count()
# Данные об авторах книг
authors = Author.objects
num_authors = Author.objects.count()
# Словарь для передачи данных в шаблон index.html
context = { 'text_head' : text _head,
'books': books, 'num_books': num_books,
'num_instances': num_instances,
'num_instances_availaЬle': num_instances_availaЫe,
'authors': authors, 'num_authors': num_authors)
# передача словаря context с данными в шаблон
return render(request, 'catalog/index.html', context)
Во второй. строке этого программного модуля был выполнен импорт следующих моде
лей: вооk (книги), Author (авторы), Bookinstance (экземпляры книг).
В первой части функции inctex() выполняются запросы к БД и выборка данных:
□ о книгах - books;
□ о количестве книг - num_books;
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 433
{% extends "catalog/base.html" %)
{% Ыосk title %)Мир книг{% endЬlock title %)
{% Ыосk header %)
<h5>{{ text_head ))</h5>
{% endЫock header %)
{% Ыосk content%)
<div class="container-fluid my-2">
<div class="row bg-success text-white mx-2">
<div class="col text-center">
<р>Добро пожаловать на сайт <еm>Мир книг</еm>. Это очень
простой веб-сайт, написанный на Django и Bootstrap.
Разработан на Python в качестве учебного примера
с использованием PyCharm.</p>
</div>
</div>
<div class="row text-center text-dark lh-2">
<h4>Сведения из базы данных</h4>
</div>
<div class="row my-2 text-white">
<div class="col mx-2 Ьg-рrimаrу">Количество книг -
{{num_books) )</div>
<div class="col mx-2 bg-primary">Ha складе в наличии -
{{num_instances)}</div>
434 Глава 10
Как можно видеть из первой строки данного листинга, эта страница является расшире
нием базового шаблона base.html.
После этого следует блок header - заголовок данной страницы { % Ыосk header %).
В этом заголовке вьmодится текст, который передан в данный шаблон в переменной
text_head из представления views. index.
Затем следует блок content. Его содержимое будет полностью перенесено в соответст
вующий блок content, который находится в базовом шаблоне. Макет этого блока сфор
мирован на основе адаптивных классов и тегов фреймворка Bootstrap и состоит из сле
дующих разделов:
□ вьmод текстовой информации;
□ вьmод сведений о числе элементов в базе данных (число книг, число экземпляров
книг, число авторов;
□ вьmод карточек с изображением книг.
□ Для вьшода сведений о числе элементов в базе данных сформированы три адаптив
ных блока, которые представляют три колонки одной строки. Эти блоки постоянно
присутствуют на странице, в них меняются только числовые данные, полученные
изБД.
□ Для вьшода карточек с изображением книг используются специальные теги Django:
□ { % if nurn Ьooks > о %) - проверяет наличие книг вБД;
□ { % for obj in Ьooks %) - организует цикл перебора найденных книг.
□ В блоке if проверяется условие - есть ли в БД записи о книгах. Если число най
денных вБД книг больше нуля, то в цикле выполняется выбор всех найденных книг
и формирование карточки по каждой книге. Карточки создаются на основе класса
Пример создания веб-интерфейса для пользователей сайта ((Мир книг» 435
<!DOCTYPE html>
<html lang="en">
<head>
{% load static %}
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale= l">
<link rel="stylesheet" href="/static/css/bootstrap.rnin.css" >
<script defer src="/static/js/bootstrap.bundle.rnin.js"></script>
</head>
<body>
<div class="container-fluid р-1 bg-prirnary text-white text-center">
<div class="row">
<div class="col-2 text-start">
<img src="{% static 'irnages/pplOO.jpg' %}" width="70"
height="70">
</div>
<div class="col-10 ">
ниг
к --п-е-ча_т_ные
__и_м_е--о~нные к -ные
--�--т е-�--
тив -.-книги
---<=n�З�
</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="{% url 'index' %}">Главная страница</а>
<а href="{% url 'index' %}">О компании</а>
<а href="{% url 'index' %}">Контакты</а>
</hб>
</div>
</div>
<div class="container-fluid">
<div class="row text-center text-primary fs-1 fw-bold">
<div>{% Ыосk header%}
{% endЫock header %}
</div>
</div>
<div class="row text-start text-body">
<div class="col-2 ">
{% Ыосk sidebar %}
436 Глава 10
{% endЫock footer%}
</div>
</div>
</body>
</html>
11
Мир книг - печатные и электронные интерактивные книги
Книги
lrltJ-81 l:liltdll
Книги
Рис. 10.6. Главная страница
сайта в формате
мобильного телефона
l2сту..... �имир,
Ц,""22(),00 ....:2:юо.00
ц
руб. ру6.
438 Глава 10
та. Для ее создания мы воспользуемся базовым шаблоном сайта (base.html), который был
рассмотрен в предыдущем разделе.
И начнем мы с сопоставления URL-aдpecoв. Для этого откроем файл \WebBooks\
catalog\urls.py и добавим в него строки, выделенные в листинге 10.9 серым фоном.
Практически так же, как и для главной страницы сайта, функция path () связьmает мар
шрут (URL-aдpec) страницы (books/) с классом в представлении views.BookListView.
as_ view (). Кроме того, здесь определено имя для ссьmки на данную страницу сайта
(name='books'). Обратите внимание, метод as_view о нужно вызвать, т. е. поставить в кон
це круглые скобки, а не просто передать ссьmку на него. В результате выполняется вся
запрограммированная работа по созданию экземпляра класса и гарантируется вызов
правильных методов для входящих НТТР-запросов от пользователей.
Конечно, мы могли бы реализовать показ списка книг при помощи обычной функции,
как это делалось для главной страницы сайта. Иначе говоря, выполнить запрос на по
лучение списка всех книг из базы данных, после чего вызвать функцию rencter () , кото
рой передать этот список, и отправить его в соответствующий шаблон страницы. Но
здесь мы воспользуемся классом, который будет наследником существующего в Django
класса ListView для отображения списка данных. В классе ListView уже реализован
функционал для того, чтобы получить и показать список книг, а значит, мы справимся
со своей задачей меньшим числом строк программного кода.
Откроем файл catalog\views.py и добавим в него класс вookListView с помощью кода лис
тинга 10.10 (изменения выделены серым фоном).
:j
from .models import Book, Author,
frazn
clas
{% extends "catalog/base.html" %}
{% Ыосk content %}
<div class="row text-center text-dark lh-2">
<h4>Сnисок книг в БД</h4>
</div>
{% if books %}
<tаЫе class="taЫe taЫe-striped taЬle-bordered text-start">
<thead>
<tr>
<th>Название</th>
<th>Aвтop</th>
<th>Жaнp</th>
<th>Обложка</th>
<th>Показать обложку</th>
</tr>
</thead>
<tЬody>
{% for book in books %}
<tr>
<td><a href="{{ book.id }}">{{ book.title }} </a></td>
<td>{{ book.display_author }}</td>
<td>{{ book.genre }}</td>
<td><img src="{{ book.photo.url }}" alt="connect"
style="max-height:lOOpx"></td>
<td><a href="{{ book.photo.url}}"
class="btn btn-primary"
target="_Ыank"> Показать</а></td>
</tr>
{% endfor %}
</tbody>
</tаЫе>
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 441
{% else %}
<р>В базе данных нет книг</р>
{% endif %}
{% endЫock %}
Здесь, как и в шаблоне главной страницы, в первой строке мы расширяем наш базовый
шаблон - { % extencts "catalog/base.html" %} , а затем определяем блок с именем content.
Внутри этого блока в цикле формируется и выдается список книг.
Сначала с использованием инструкции if проверяется, есть ли в БД записи с информа
цией о книгах - { % i f books % } • Если в БД есть хотя бы одна запись о книге, то создает
ся таблица Bootstrap, если в БД нет записей о книгах, то пользователю будет выдано
сообщение «В базе данных нет книг».
В теге Bootstrap <tаЫе> создано пять столбцов. Сначала в теге <theact> формируется
«шапка» таблицы, а затем в цикле { % for book in books %} столбцы таблицы заполняют
ся следующей информацией:
□ {{ book.title }} - название книги;
□ {{ book.display_author }} - автор (авторы) книги;
□ {{ book.genre }} - жанр книги;
□ {{ book.photo.url }} - изображение обложки книги;
□ { { book.photo.url}} -ссылка на изображение обложки книги.
Код внутри цикла представлен следующей инструкцией вывода названия книг:
<а href="{{ book.id }}">{{ book.title }}</а>
Здесь текст с названием книги представляет собой ссылку для перехода на страницу
с полной информацией об этой книге. В качестве параметра в URL-aдpece передается
идентификатор книги в БД (ьооk. ict).
При вьmоде изображения обложки книги задано ограничение изображения по высоте:
style="rnax-height:lOOpx"
Таким образом, независимо от размера исходных изображений, все обложки будут вы
ведены в едином масштабе. Для того чтобы можно было посмотреть на обложку в пол
ном размере, в последней колонке вьmедена кнопка со ссылкой на файл с изображени
ем. Нажав на нее, пользователь может в отдельной вкладке браузера увидеть обложку
в полноформатном виде.
Теперь нужно открыть файл с базовым шаблоном по пути
\WebBooks\templates\catalog\base .html
и указать URL-ссылку для пункта бокового меню Все книги, как показано в лис
тинге 10.12 (изменения выделены серым фоном).
{% Ыосk sidebar %}
<nav class="nav flex-column">
Глава 10
В этой строке мы указали, что при выборе опции меню Все книги будет выполнен пе
реход к URL-преобразованию с именем 'books ', а в нем происходит обращение к классу
�•ИC•"JПJ Мир книг - печатные и
э
4t
()
13э интерактивные к
!@
На нашем сайте вы можете получи
электронном виде
Все Добро пожаловать на сайт Мир к1
использованием PyCha
Все
авторы
Сведения из базы д
Кол.1чество На складе в
книr - 5 наличии - 9
Рис. 10.7. Переход к странице Все книги на главной странице сайта «Мир книг»
о
т
е
е
л о
н
Ильф,
Петров
ю н
П рикл че ия
i:Нihiii
т
>i
Во>iна и миn
З
оло
Толс о>i
т
Проза
.,;.;;;;;;
Пушкин Проза
i,Нi!iiii
Рис. 10.8. Страница Все книги сайта «Мир книг»
Пример создания веб-интерфейса для пользователей сайта ((Мир книг» 443
Теперь на главной странице нужно щелкнуть левой кнопкой мьШiи на ссьmке Все кни
ги в боковом меню (рис. 10.7).
Если все сделано правильно, то будет выдана страница с полным списком книг, кото
рые занесены в БД (рис. 10.8).
На этой странице названия книг показаны в синем цвете, а это признак того, что они
являются ссьmками для перехода на страницу с детальной информацией о книге. Одна
ко если щелкнуть мышью на такой ссьmке (на названии книги), то ничего не произой
дет, поскольку мы еще не создали страницу для показа полной (детальной) информации
о книге. Приступим к этому процессу.
Практически так же, как и для страницы сайта ьooks, функция path () связьmает маршрут
(URL-aдpec) страницы (ьooks/<int:pk>) с классом в представлении views.BookDetailView.
as_view () . Кроме того, здесь определено имя для ссьmки на данную страницу сайта
(name='book-detail').
444 Глава 10
Теперь нужно создать шаблон для вьщачи пользователю данных о книге с именем
book_detail.html и поместить его по следующему пути:
\WebBooks\templates\catalog\book_detail.html.
В этом шаблоне напишем код, приведенный в листинге 10.15.
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 445
{% extends "catalog/base.html" %}
{% Ыосk content %}
<div class="container text-start">
<div class="row my-2">
<hl>Название книги - "{{ book.title }}"</hl>
</div>
<div class="row my-2">
<p><strong>Aвтop:</strong>
{% for author in book.author.all %}
<а href="">{{ author.first name }} {{author.last_name}}</a>
{% endfor %}
</div>
<img src="{{ book.photo.url }}" alt="connect"
style="max-height:200px">
<а href= "{{ book.photo.url}}"
class="btn btn-primary"
target="-Ыank"> Показать</а>
'
<div class="row my-2">
<div class "col">
=
</div>
{ % enclЫock %}
Сначала вьmодятся две строки: название книги, автор (авторы). Так как авторов может
быть несколько, то здесь с использованием инструкции if организован цикл перебора
всех авторов, а в теле цикла выводятся имя автора (author.first_name), фамилия автора
(author.last _name).
После этого вьmодится изображение обложки с ограничением по высоте 200 рх, а ря
дом с ней кнопка со ссьmкой на URL-aдpec изображения обложки. Нажатие на эту
кнопку обеспечивает вывод обложки в полном размере в отдельной вкладке браузера.
Под обложкой выводится цена книги (ьook.price). После этого следует строка для вьmо
да аннотации к книге (ьооk.summary).
Затем с использованием тегов Bootstrap создано четыре адаптивных блока, в которых
вьmодятся:
□ жанр книги (book.genre);
□ ISBN книги (ьооk. isbn);
□ язык, на котором написана книга (book.language);
□ издательство (bo9k.puЫisher).
В заюnочительном блоке с инструкцией if организован цикл, в котором вьmодятся све
дения о состоянии конкретных экземпляров данной книги. Здесь интересным методом,
который мы не встречали ранее, является метод book.bookinstance_set.all. Этот метод
Django формирует автоматически. Он обеспечивает получение. множества записей
о состоянии экземпляров (вookinstance) конкретной книги (вооk):
{% for сору in book.bookinstance_set.all %)
<!-- итерации по к�ому экземпляру книги -->
{% eпdfor %}
Этот метод создан потому, что в модели данных бьmа указана связь «один ко многим»
(одна книга-> много экземпляров книг). С учетом этой связи Django самостоятельно
конструирует метод «обратного просмотра» (reverse lookup), которым можно восполь
зоваться. Имя этого метода создается автоматически с использованием символов
в нижнем регистре и состоит из имени модели, в которой бьm объявлен первичный
ключ - ForeignKey (в нашем случае это bookiпstance), за которым следует выражение
_set. В нашем примере метод, созданный для модели вооk, имеет имя book.bookinstance_
set. В приведенном шаблоне также бьm указан параметр all для получения всех запи
сей из таблицы БД (book.bookinstance_set.all).
К настоящему моменту мы создали все необходимое для показа полной информации
о каждой книге. Запускаем наш сервер (python manage.py runserver) и открьmаем браузер:
bttp://127.0.0.1:8000/. На главной странице в меню выбираем опцию Все книги и полу
чаем страницу со списком книг. Если теперь щелкнуть левой кнопкой МЬШIИ на назва-
Пример создания веб-интерфейса для пользователей сайта ((Мир книг» 447
нии книги, например Война и мир, то будет выдана страница с полной информацией
об этой книге (рис. 10.9).
Обратите внимание, что на данной странице фамилия и имя автора имеют синий цвет, а
это признак того, что они являются ссылкой для перехода на страницу сайта с инфор
мацией об авторах. Пока эта ссьшка не работает, т. к. мы еще не создали соответст
вующую страницу и не реализовали механизм доступа к ней. Это мы сделаем несколь
ко позже.
---- --- • ------- - - - - -- - - -- -
I,Jtl"•1"fliJ
:1,1· "'"i
f!111M1
Ан11От•цюс •вОl"!ма и мир• л. н. Толсюrо • IСНИПI на есе времi!т. Ка,: буАто окз сущесrвоВаJ\i
ы:еr� нi1Сfо11ько знакомым -rся "ll!IOCТ, ед11а 1,!1,1 открываем rrep111,II! страницы ромжа,
мюольхо naмяtliw Ml!Ot'Иt tro )1111-ЮАЫ oxara 11 CIJIIO\ ntреый бал �и РОаово.i, J\'jНнal!
t<ОЧ� е оrрздном, !(l;ЯЭь АНдРей II срзжt>1и11 nри Aycrep.nvщe•• cueнw 'мирноi\". сеыекноя :11:1fЭЮ!
с:щ111я1ОТся IС.'lртмнами. им11�ощи�1;; знэчем�ае AIIЯ хода есей мироюй ж:1'0/ЖИ. но дл,� Том:rою о+1й
ра!!НОЦ!!НЮ:,1, СРЭ.!НW е едином ПOTOl(i! spet.l!!HИ. Кажд!,1.-! ЭIПИ)ОJ\ -н не ТО,111,Ш ДАJ1 рЭЗ8ИТ1111
ООЖf! а, НО и UK О№О ,о бесЧИОli!ЮIЫХ nро,вМt<и.-! ХИ1Н>1, коrорую �ит яюбмп. 1'олстоi\.
Инвонr.1рнык номер: 6
Ст;атус: >оомм11ра книrи: На С!U!аДе
Все книги
Название книги - "12 стульев"
Все авторы
н,ны+м
Список iJ8ТOpos
Аннотация: Это роман, написанный почти век назаА а кажется,. '<ТО совсем недавно. Ero
цитируют все, даже те, кто не прочел ни страницы текста и не смотрел ни одной жранизации, а
class BookListView(ListView):
model = Book
context_object_name = 'books'
paginate_by = 3
Как только в базе данных появится более трех записей, представление начнет форми
ровать постраничный вьmод данных (страницы будут передаваться шаблону). К раз-
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 449
личным страницам можно будет получить доступ при помощи параметров GЕТ
запроса. Например, к странице 2 можно получить доступ через URL-aдpec /catalog/
books/?page=2.
Теперь, когда задан вывод данных постранично, нам нужно добавить функционал
переключения между страницами в шаблон страницы. Поскольку целесообразно ис
пользовать этот механизм для всех списков на сайте, то мы пропишем его в базовом
шаблоне сайта.
Откроем файл \WebBooks\templates\catalog\base.html и после блока content вставим блок, отве
чающий за постраничный вьmод (листинг 10.17, изменения выделены серым фоном).
{% Ыосk sidebar %}
<nav class="nav flex-column">
<а class="nav-link" href="{% url 'books-list' %}">Все книги</а>
<а class="nav-link" href="{% url 'authors-list' %}">Все авторы</а>
</nav>
{% endЫock sidebar %}
</div>
<div class="col-10" >
<div class="row text-center">
{% Ыосk content%}
{% endЫock content %}
</div>
</div>
</div>
</div>
<div class="container-fluid">
<div class="row bg-info text-center text-dark sпall lh-sm pt-2 m:i::- ">
{% Ыосk footer %}
<p>Copyright ООО "Интеллектуальные информационные системы",
2023. Все права защищены</р>
{% endЬlock footer%}
</div>
</div>
</body>
</html>
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 451
Чтобы более детально изучить структуру кода класса pagination, выделим его из базово
го шаблона и покажем с учетом правильных отступов:
<!-- пагинатор -->
<div class="pagination">
<span class="step-links">
{% if page_obj.paginator.ni.дn__pages > 1 %)
{% if page_obj.has__previous %)
<а href="?page=l">« Первая</а>
<а href="?page={{ page_obj.previous__page_numЬer ))">Предыдущая</а>
{% endif %)
<span class="current">
Стр. {{ page_obj.numЬer )) из {{ page_obj . paginator.nшn__pages )} .
</span>
{% if page_obj.has_next %)
<а href="?page={{ page_obj.next__page_numЬer ))">Следующая</а>
<а href="?page={{ page_obj.paginator.nшn__pages ))">Предыдущая » </а>
{% endif %}
{% endif %)
</span>
</div>
<!-- пагинатор -->
В этом коде сначала выполняется проверка, что число вьmодимых страниц больше
одной (if page_obj.paginator.nшn__pages > 1) . Если число выводимых страниц меньше или
равно единице, то выводимый список нет смысла разбивать на страницы. Если же спи
сок не помещается на одной странице, то далее делается проверка, вюпочен ли меха
низм постраничного вывода. Если разбивка списка на страницы включена, то после
вьmода первой страницы списка отображаются следующие элементы:
□ номер текущей страницы (page_obj.numЬer);
□ общее число страниц (page_obj.paginator. ni.дn__pages);
□ надписи со ссылками на страницы Следующая и Предыдущая.
Здесь параметр page_obj является объектом типа Paginator, который станет создаваться
каждый раз, когда будет применяться постраничный вывод данных для текущей стра
ницы. Он позволяет получить всю информацию о текущей странице, о предыдущих
страницах, об общем числе страниц и т. п.
В теле класса pagination есть два блока с инструкцией н:
□ { % if page_obj.has_previous % ) - проверка, поступил ли запрос на переход к преды
дущей странице;
□ { % if page_obj. has_next % ) - проверка, поступил ли запрос на переход к следующей
странице.
Если условие проверки соблюдается, то выполняется переход к заданной странице.
Здесь используем выражение _<href="?page=> для получения URL-aдpeca нужной стра
ницы.
Если мы теперь загрузим страницу со списком книг, то под ним увидим блок организа
ции постраничного вьmода данных (рис. 10.11).
Нажмите в нем на ссьшку Следующая - будет вьшедена следующая страница со спи
ском книг и появится ссьшка для возврата на предыдущую страницу (рис. 10.12).
452 Глава 10
Пострани�ный
.,;.;;;;;;
выюд списка
книr
Ст . 1 ю 2. СледуJОЩая Предыдушая »
р
,.,.
� .,п.. Мир книг - печатные и электронные интерактивные книги 1
ах,
Все книги Список книг в БД
Все авторы На::�вание Автор Жанр Обложка Пока::�ать о6пожку
{% extends "catalog/base.html" %}
{% Ыосk content %}
454 Глава 10
Здесь, как и в шаблонах других страниц страницы, в первой строке мы расширяем наш
базовый шаблон- {% extends "catalog/base.htrnl" %}, а затем определяем блок с именем
content. Внутри блока в цикле формируется и выдается список авторов книг. В этом
шаблоне для доступа к данным об авторах используется объект author_list.
Сначала с помощью инструкции if проверяется, есть ли в БД записи с информацией об
авторах- { % if author_list % J. Если в БД есть хотя бы одна запись об авторе книги, то
создается таблица Bootstrap, если в БД нет записей об авторах, то пользователю будет
выдано сообщение «В базе данных нет авторов».
В теге Bootstrap <taЬle> создано три колонки. Сначала в теге <theact> формируется
«шапка» таблицы, а затем в цикле {% for author in author list.all %) столбцы таблицы
заполняются следующей информацией:
□ { { author.first_name )} - имя автора;
Здесь текст с именем и фамилией автора представляет собой ссьmку, которая дает
возможность перейти на страницу с полной информацией об этом авторе. В качестве
параметра в URL-aдpec передается author.id.
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 455
Здесь мы создали переход на страницу с авторами книг (теперь мы можем смело это
сделать, поскольку у нас имеется соответствующее URL-преобразование). Для выдачи
списка авторов у нас все сделано. Загружаем главную страницу нашего сайта и в левом
меню щелкаем левой кнопкой мыши на ссьmке Все авторы - откроется страница
с полным списком авторов (рис. 10.13).
1 А11ександр..JJ.\!У.!!Ш!:!
11,Ф!Р.11
j
fл;то,сr2'
;,;;;;;;;
. Илья Иль!Р..
Следует обратить внимание, что список авторов разбит на страницы. Это автоматиче
ски сработал блок разбивки данных на страницы, который мы ранее создали в базовом
шаблоне.
Практически так же, как и для страницы сайта authors, функция path() связывает
маршрут (URL-aдpec) страницы ( authors/<int:pk>/) с классом в представлении views.
AuthorDetailView.as_view(). Кроме того, здесь определено имя для ссьmки на данную
страницу сайта ( name= ' authors-detail').
Поскольку мы заранее не знаем, о каком авторе будет запрошена информация, то
в этом случае потребуется функция path с параметрами формирования URL-aдpeca
(authors/<int:pk>/). Здесь угловые скобки <...> необходимы для того, чтобы получить зна
чение из URL-aдpeca. Преобразователь int обеспечивает гарантированное получение
целочисленного параметра, а параметр pk (primary key - первичный ключ) служит для
получения идентификатора автора из БД.
Здесь мы воспользуемся классом, который наследуется от существующего в Django
класса DetailView (отображение элемента из списка данных). В классе DetailView уже
реализован функционал для того, чтобы получить и показать информацию о конкрет
ном авторе, а значит, мы справимся со своей задачей меньшим объемом программного
кода.
Откроем файл catalog\views.py и добавим в него класс AuthorDetailView с помощью кода
листинга 10.23.
Пример создания веб-интерфейса для пользователей сайта <<Мир книг» 457
class AuthorDetailView(DetailView):
model = Author
Теперь нужно создать шаблон для выдачи пользователю данных об авторе с именем
author_detail.html и поместить его по следующему пути:
\WebBooks\templates\catalog\author_detail.html.
В этом шаблоне напишем код листинга 10.24.
! лИСТИ:r
10.24. Измененный код фaiina \WeЬВooks\t8mp1ates\catalog\author�detail.html
{% extends "catalog/base.html" %}
{% Ыосk content %}
<div class="container text-start">
<div class="row my-2">
<h4>{{ object.first_name }} {{author.last_name}}</h4>
<р>Родился - {{author.date_of_birth}}</p>
<р>Фото (портрет) </р>
<p><img src= "{{ author.photo.url })"
alt="coпnect" style= "max-height:200px"></p>
<div class= "row my-2">
<div class="col-2 my-2">
<а href= "{{ author.photo.url}J" class= "btn btn-primary"
target="_Ыank"> Показать</а>
</div>
</div>
<div class= "row my-2">
{{author.aЬout)J
</div>
458 Глава 10
</div>
</div>
{ % endЫock % }
Здесь, как и в шаблонах других страниц, в первой строке мы расширяем наш базовый
шаблон - { % extends "catalog/base.html" % } , а затем определяем блок с именем content.
Внутри этого блока выдаются данные о конкретном авторе:
□ obj ect. first_narne - имя;
□ author.last_narne - фамилия;
□ author. date_of_Ьirth - дата рождения;
□ author.photo.ur1 - портрет;
□ author.aЬout - краткая характеристика автора.
Обратите внимание, что в этом. модуле сведения об авторе бьmи получены из объекта
object и из объекта author.
К настоящему моменту мы создали все необходимое для показа полной информации
о каждом авторе. Запускаем наш сервер (python manage.py runserver) и открьmаем брау
зер: Ьttp://127.0.0.1:8000/. На главной странице в меню выбираем опцию Все авторы
и получаем страницу со списком авторов. Если теперь щелкнуть левой кнопкой мьШiи
на имени или фамилии автора, например Лев Толстой, то будет выдана страница
с полной информацией об этом авторе (рис. 10.14).
Фото (noprperJ
4:1:114·14
Лев Николаевич Толстой (28 августа 1828, Ясная Поляна, Тульская rуберния), Один из
наиболее изеест11ых русских писателей и uыслителей, один из величайших пис.ате11ей
романисюв мира. Участник обороны Севастополя. Просветите.ль, публицист,
религиозный мыслитель, Ч./lен-коррес.nондент Имnера-rорской Академии наук. Был
1-юминирован на Нобелевскую премию no 11tпературе (1902, 1903, 1904, 1905). Писаrель.,
ещё при жюни призканный rлавой русской лшературы. Творчество Льва Толстого
ознаменовало новый этап в русском и мировом реализме, выступив мостом между
классическим романом XIX века и литературой ХХ: века. Наиболее известны такие
произведения Толстого, как ром.а1-1ы «Вой1-1а и uир•, «Анна каренина•, «Воскресение и др.
14;;;;;
Ц-: 210,00 руб.
def contact(request):
text head = 'Контакты'
narne = 'ООО "Интеллектуальные информационные системы"'
address = 'Москва, ул. Планерная, д. 20, к. 1'
tel = '495-345-45-45'
email = 'iis info@mail.ru'
# Словарь для передачи данных в шаблон index.html
context = {'text_head': text_head,
'narne': narne, 'address': address,
'tel': tel,
'email': email}
# передача словаря context с данными в шаблон
return render(request, 'catalog/contact.html', context)
Это достаточно простой и уже знакомый нам код. Здесь нет обращений к Бд, просто
сформировано несколько текстовых переменных, все их значения упакованы в словарь
context, который передается в шаблоны: about.html и contact.html. Теперь необходимо соз
дать эти шаблоны.
Для вывода сведений о компании создадим шаблон с именем about.html и поместим его
по следующему пути:
\WebBooks\templates\catalog\about.html.
В этом шаблоне напишем код листинга 10.28.
{% extends "catalog/base.html" %}
<head>
{% load static %}
</head>
{% Ыосk content %}
<!-- Карусель -->
<div class="container">
<div id="carouselExarnpleControls" class="carousel slide" data-bs-ride="carousel">
<div class="carousel-inner">
<div class="carousel-item active">
<img src=" {% static 'images/ai.jpg' % }" style="height: 200рх;"
class="d-Ыock w-100 " alt="image">
<div class="carousel-caption d-none d-md-Ыock">
<h2 class="text-white">Иcкyccтвeнный интеллект</h2>
<hЗ class="text-white">{{raЫ}}</hЗ>
</div>
</div>
<div class="carousel-item">
<img src=" {% static 'images/road.jpg' % }" style="height: 200рх;"
class="d-Ыock w-100 " alt="image">
<div class="carousel-caption d-none d-md-Ьlock">
462 Глава 10
Арт-объекты
</button>
</h2>
<div id="collapseThree" class="accordion-collapse collapse"
aria-laЬelledЬy="headingТhree" data-bs-parent="#accordionExaпple">
<div class="accordion-body">
<strong>Oбpaбoткa изображений.</strоng> Создаем уникальные изображения
с использованием систем машинного зрения и искусственного интеллекта.
</div>
</div>
<!-- Аккордеон элемент 4-->
<div class="accordion-item">
<h2 class="accordion-header" id="headingFour">
<button class="accordion-button collapsed" type="button"
data-bs-toggle="collapse"
data-bs-target="#collapseFour"
aria-expanded="false" aria-controls="collapseThree">
Интерактивные электронные книги
</button>
</h2>
<div id="collapseFour" class="accordion-collapse collapse"
aria-labelledЬy="headingFour" data-bs-parent="#accordionExaпple">
<div class="accordion-body">
<strоng>Интерактивное oбyчeниe</strong> Разрабатываем
интерактивные обучающие пособия, учебники, электронные
книги для студентов и школьников.
</div>
</div>
</div>
<!-- Аккордеон конец-->
</div>
</div>
<!-- пустые колонки справа от аккордеона-->
<div class="col-3"></div>
</div>
{% endЬlock %)
Листинг данного шаблона достаточно длинный, но не стоит этого пугаться. Здесь пока
зан пример использования на НТМL-страницах двух новых элементов Bootstrap: «кару
сель» (carousel) и «аккордеон» (accordion). Именно эти два элемента занимают большую
часть программного кода. Это достаточно популярные элементы интерфейса, которые
используются на страницах современных сайтов. «Карусель» позволяет создать область
автоматической прокрутки слайдов в «шапке» страницы, а «аккордеон» - группу рас
крьmающихся списков. Блоки программного кода с этими элементами выделены стро
ками с соответствующими комментариями.
Для вывода сведений с контактными данными компании создадим шаблон с именем
contact.html и поместим его по следующему пути:
\WebBooks\templates\catalog\contact.html.
В этом шаблоне напишем код листинга 10.29.
Пример создания веб-интерфейса для пользователей сайта «Мир книг» 465
<div class="col-2"></div>
</div>
</div>
{% endЬlock %}
Сведения о компании
Дорожная инфраструктура v
Арт-объекты
<div class="container-fluid">
<div class="row bg-warning text-center">
<hб>
<а href="{% url 'index' %)">Главная страница</а>
<а href="{% url 'atout' %)">О компании</а>
<а href="{% url 'contact' %)">Контакты</а>
</hб>
</div>
</div>
Искусственный интеллект v
Дорожная инq>раструктура А
Системы распоэнавания.
Разрабатываем систе мы
распознавания об"Ы!ктов дорожной
инфраструктуры с использованием
нейронных сетей.
V
Арт-объекты
Интер «аккордеона»
е книrиv
Расширение возможностей
администрирования сайта «Мир книг»
и создание пользовательских форм
В предьщущих главах мы создали сайт «Мир книг», который позволяет пользователям
получать из каталога списки книг и авторов. И сейчас каждый посетитель сайта имеет
доступ к одним и тем же страницам и типам информации из базы данных.
Однако хотелось бы предоставить пользователю индивидуальные услуги, которые за
висят от его предпочтений и предьщущего опыта использования сайта и его настроек.
Например, возможность добавлять на страницы сайта свою информацию, что актуаль
но для интернет-магазинов, социальных сетей, блогов и прочих подобных ресурсов.
В этой главе мы расширим возможности нашего сайта «Мир книг», добавив в него
счетчик посещений домашней страницы, функционирующий на основе сессий. Этот
относительно простой пример покажет, как с помощью сессий реализовать анализ по
ведения на сайте анонимных пользователей.
Мы также организуем на сайте «Мир книг» поддержку пользовательских аккаунтов и
таким образом продемонстрируем аутентификацию, разграничение уровней доступа,
сессии и пользовательские формы.
В этой главе будут рассмотрены следующие вопросы:
□ сессии в Django;
□ создание страниц для авторизации пользователей в Django;
□ организация проверки подлинности входа пользователя в систему;
□ добавление к сайту страницы для создания заказов на книги;
□ формы и управление формами в Django;
□ как создать форму для ввода и обновления информации на сайте на основе класса
Foпn();
□ как создать форму для ввода и обновления информации на сайте на основе класса
ModelFoпn().
470 Глава 11
Этот API имеет и другие методы, которые большей частью используются для управле
ния файлами cookie, связанными с сессией. Например, существуют методы проверки
того, что cookie поддерживаются клиентским браузером, другие методы служат для
установки и проверки предельных дат жизни cookie, а также для очистки хранилища от
просроченных сессий.
главной страницы через переменную context. Для показа значения этой переменной
добавьте в шаблон главной страницы сайта несколько строк кода \WebBooksltemplatesl
cataloglindex.html из листинга 11.2 (изменения выделены ·серым фоном).
</div>
{% endЫock content %}
Книги
Запустим наш сервер и несколько раз вьmолним вход на главную страницу. Значение
числа посещений будет изменяться всякий раз при входе на главную страницу
(рис. 11.2).
Несмотря на то что у нас пока нет никаких разрешений на добавление к нашему сайту
каких-либо пользователей, если мы захотим это сделать в будущем, то будет намного
проще добавлять их к уже созданной группе с заданной аутентификацией. И админист
ративная панель сайта предоставляет наиболее быстрый способ создания соответст
вующих ·групп и аккаунтов.
Итак, запускаем сервер разработки и переходим к административной панели сайта
(bttp://127.0.0.1:8000/admin/). Заходим на сайт при помощи параметров аккаунта су
перпользователя (имени пользователя и пароля). Самая верхняя страница панели адми
нистратора показьmает все наши модели. Для того чтобы увидеть записи в разделах
Authentication и Authorisation, вы можете нажать на ссылку Группы или Пользова
тели в разделе ПОЛЬЗОВАТЕЛИ И ГРУППЫ (рис. 11.4).
0 Администрирование сайта I А; Х +
� ➔ С Ф 127.0.0.1:8000/admin/
Администрирование OJango
ДОБРО ПОЖАЛОВАТЬ, ANATOLY ОТКРЫТЬ САЙТ I ИЭМЕНЫТЬ ПАРОЛЬ I ВЫЙТИ
Администрирование сайта
fATALOG , •\
Последние действия
Autlюrs + Добавить ✓ Изменmъ
+№з
+№2
Рис. 11.4. Разделы административной панели сайта для создания групп и пользователей
В первую очередь давайте создадим новую группу - нажмите для этого на ссылку
+Добавить в строке Группы. Введите для нее имя пользователи сайта (рис. 11.5). Для
этой группы не нужны какие-либо разрешения, поэтому просто нажмите кнопку
СОХРАНИТЬ, и вы перейдете к списку групп.
Теперь давайте создадим пользователя. Для этого возвращаемся на главную страницу
административной панели и нажимаем ссылку +Добавить в строке Пользователи, по
сле чего откроется окно со списком пользователей (рис. 11.6).
Расширение возможностей администрирования сайта <<Мир книг» ... 477
Администрирование Django
ДОБРО IЮЖАЛОВАТЬ ANATOLY ОТХРЫТЬ САЙТ / ИЗМЕНИТЬ ПАРОЛЬ/ ВЫЙТv\
. ,,:Л%1.1,��
начало,пользов�!���
�
Добавить группа
Genres + Добавить
I Q Фильтр
Languages + Добавить
admin I запись в журнале I С, • i
о
Publishers +добавить
,1 admin ! запись в журнале I с.8
о
admin I запись в журнале I С,
а<!�1� 1 зanи�ь,:i_�P,И,aJteiC:,_: 1
statuss
8ьlбра'ТЬ!К1! 0
Удержива?tп �ControJ� (мл.и �Command* �а ас),
ПОЛЬЗОВАТЕ/\И И ГРУЛ11Ы :•
. ' чюбы ас�брап, нecxcnьk.Q зн<1�ений,
7
Группы +добавить
'
+Добаоитъ
ФИЛЬТР
Authors а.
! статус персонала
Найти
Вookinslances +добавить
все
+ДО6авmъ .., да
Выполнить В1..1бра:но о обlrоКТО• .-. 1
8ooks Дейсmие:
+ ДОбавmъ
Her
! статус
Genres
« +добав.rь неr
lпольхн,атель
S\atuss
,1. активный
ПОЛЬ30-8АТЕЛМ и ГРmnы ' {\t ■ все
+Добавить
rь
Груnnы да
+ДОбаеи
Нет
nonь30831'enм
nы
Администрирование Django
ДОБРО ПОЖАЛОВАТЬ ANATOlY ОТКРЫТЬ САЙТ/ ИЗМЕНИТЬ ПАРОЛЬ/ ВЫЙТИ
Добавить пользователь
CATAlOO
Authors Сначала введите имя пользователя и пароль. Затем вы сможете ввести больше
+Доба6.ТЬ
информации о пользователе.
Вооk instances +добавить
Имя пользователя:
ВOoks + Добэвкть
06Jt:1.rrм•l4DE nом;, Не боли 1 50 Ci'l"'IOЛOe. TOl'lw.o бук.аw., �фры
исимамw@/.J+J./_.
Genres + Добааить
Грумы + Добаенть
Подтверждение nаропя:
Пооьэоеате1111
�К';_��
·Ийi@!
Сохранить и продмж1пъ реда,сrироаанме
Рис. 11.7. Окно для ввода новых пользователей в административной панели сайта
((
PuЫishers + Добавить
statuss +добавить
llepcol!anьttaя иЖIЮi)маЦIIЯ
Имя:
Пользоватеnи +добавить
Фамилия:
---- -- -----
Адрес электронной
ПОЧТЬI:
СдТАLОО •'
Права достуf1<! • • • •
/wtho,s +добзо.-ть
С1 Активный
Вооk instances +добамть On.wr..n, �.,. nоп��.дмж..,.ещ1� а,ст'Иан.�м, У�п ату стмещ •меатоудаntж.м �ОМ 1е:nмсм.
Genres + Доове.-ть
О Статус суnерпольз оватеnя
L.anguages +Добаокть YK8Jt.1UIП, '(ТО ПOl'lbIOIU'!W'Jtb tl!W"T а.:. nр•.в• 6.:J "•ноrо М)[ наа1,нN•t-1м.
Publishers +Добаеить
Группы:
statuss + Добае.-ть
Q.
Пользователи сайта
ПОЛЬЗОВАТЕ/11111 ГPmnЬI
«
Грумы +добзоить
Польэов.атеnи +добаекть В.lбратьосео
Гpynnr.t. 1( которwм rtрНН8ДМЖlft Jil.itЧ�.J:i OOJ'!ii,J!Ouл,Jlt,.,, Г'!Qnьl!QIU't'ff\l, l"ЮА!,'ЧНТ IIOf!
r.p••e. ука.нwнь�ое-а "ucдo+i м:а l!ro/M групп. YД�JIQl&l;iтt- ·c�{w,.i NComm.arxf' �
М.с). >Пс6ы аь�брп. н.а,:олwш ,1.ts�IG(.
-· .. _
. . . ._
О. i Фмьтр
. . . _.. _.. ::::..1 о
admin I запись в журнале I с, 1
admin I запись в журнале I с, ..
■· ()•
Рис. 11.9. Блок задания прав доступа пользователей в административной панели сайта
480 Глава 11
Genres + Добавкть
дата регмстрации: Дата: ! 14,01.2023 Сеrодl!Я 1
Languages + Добавить
-
PuЬlishers +добавить Время: 23:14:30 Сейчас10
statuss +добавить
ПОЛЬ306АТfЛИ И ГРУППЫ
Группы +доба.вить
Сохранить и добавить д!JУ\'ОЙ объект
l&MiiiШI
Сохранить и nродоruкить редактиРООан,1е
Польэоаатели +добавить
Рис. 11.10. Блок Важные даты и кнопочная панель в административной панели сайта
�.Начало.попЬЗОВЭтел;��ыrntт�l�f
h
,,� � : =;
'
.. .'' '" � � . �
��
1,' • " "/,'
' " " ;,
Getves +Д<Юа0"1Ъ
Действие: v Выполнить I Вы61)ано О объектов и> 2
tangw,gos +Добавить
Pul>lislt<r., +до6ааить
о ИМ11 fЮ11ЪЭОВАП/111 ..,. АДРm ЭЛЕКТРОНно.i ПО'ПЫ ИМЯ ФАМКЛИЯ СТАТУС ПЕРСОНАЛА
staluss +добаокть
о anatoly anзlJ)ost@mail.ru t,
О Тестер_1 �H.ru Тестер Тестер о
« nользоадтели и ГPrnnы 2 ООПЬ306ЗТелИ
Ноаь1й
Груnnы +добаокть
Поnь30ватепм +до6аокть
Вот и все! Теперь у нас есть учетная запись «обычного пользователя» сайта, которую
можно использовать для тестирования работы сайта (после того, как мы добавим стра
ницы входа пользователей в систему).
Следующий шаг - создайте каталог (папку) registration в папке templates. Затем в эту папку
добавьте шаблон - файл login.html (рис. 11.12).
Затем в файле login.html напишите код листинга 11.4.
{% extends "catalog/base.html" %)
{% Ыосk content %}
482 Глава 11
..
о'
с;_ Т II WorWJюoks
► llvenv 11,1<11:.
Т 11 \11/ebBooks
Рис. 11.12. Создание каталога
► 11 catalog registration в папке terrplates
► 11 med1a и файла login.html
► llstat,c
Т II templдtes
► 11 catalog /_
��а
Т II reg1stratюn
Т II WebBooks
{% if form.errors %)
<р>Ваши имя пользователя и пароль не совпали.
Пожалуйста, попробуйте еще раз.</р>
{% endif %)
{% if next %)
{% if user.is_authenticated %}
<р> Вы не имеете доступа к этой странице.
Войдите в систему с другими параметрами</р>
{% else %)
<р> Войдите в систему, чтобы увидеть эту страницу .</р>
{% eпdif %)
{% endif %)
<form method="post" action="{% url 'login' %)">
{% csrf_token %)
<div class="row my-2 text-center">
<div class="col-4">
<tаЫе class="taЫe taЫe-bordered my-2 text-start">
<tr>
<td>{{ form.username.label_tag ))</td>
<td>{{ form.username ))</td>
</tr>
<tr>
<td>{{ form.password.label_tag })</td>
<td>{{ form.password ))</td>
</tr>
</tаЫе>
</div>
<div class="col-8"></div>
</div>
<div class="row my-2 text-start">
<div class="col-4">
<input type="suЬmit" value="Bxoд" />
<iпput type="hidden" name="next" value="{{ next ))" />
Расширение возможностей администрирования сайта «Мир книг» ... 483
0 127.0.0.1:8000/account. is log•nl
_: ;;:.,;:,....
.-_
..,__-
V
�-- .-------)'.
URL·aдpec проф ля
и
Page not found
Request Method: GET
{404)
YoU're seeing this епоr Ьecause you have DEBl.16 = тrue in уоuт DJaлgo settings file. Change that !о false, and
Django will disptay а standard 404 page..
Теперь, если повторить вход в систему, то ошибка больше выдаваться не будет и поль
зователь будет успешно перенаправлен на домашнюю страницу сайта.
Если же вы перейдете по URL-aдpecy выхода http://127.0.0.1:8000/accountsЛogout/, то
увидите, что пользователь вьmеден из системы, но это (по умолчанию) будет показано
в окне панели администратора сайта (рис. 11.15).
Но это не то, что нам нужно, такое окно должны получать только пользователи, у кото
рых есть статус is_staff, т. е. персонал, обслуживающий сайт. Чтобы этого не происхо
дило, создадим шаблон страницы выхода из системы (файл templates\registration\logged_
out.html) и внесем в этот файл код листинга 11.6.
{% exteпds "catalog/base.html" %}
{% Ыосk сопtепt %}
<р>Выход из системы!</р>
<а href="{% url 'logiп'%}"> Нажмите на эту ссылку для входа в систему</а>
{% endЫock % }
Расширение возможностей администрирования сайта «Мир книг» ... 485
0 Не авторизован i Админ><стра, Х + V
URL-aдpec выхода
пользователR по
умолчанию
успешном
выходе
Не авторизован
Thanks for spending some quality time with the web site today.
Войти снова
Рис. 11.15. Окно с сообщением об успешном выходе из системы панели администратора сайта
Этот шаблон очень прост. Он выводит сообщение о том, что вы вышли из системы,
и предоставляет ссылку, которую вы можете нажать, чтобы вернуться на страницу вхо
да в систему.
Попробуем снова перейти на страницу выхода из системы. Если вы опять видите стра
ницу выхода из системы панели администратора сайта (см. рис. 1 1 .15) 1;1место своей
собственной страницы выхода, то пугаться не стоит. Попробуйте изменить настройку
INSTALLED_APPS вашего проекта в файле settings.py и убедитесь, что строка 'django.
contrib. admin' стоит после строки с вашим приложением 'catalog' (рис. 11.16).
0 127.0.0.1:8000/a-ccou nt"1ogout/ Х + V
f- ➔ с ф 127.0.0.1:8000/accounts/Jogout/
URL·aдpec оыхода
--&��
nользоеат�я по умолчанию
Выход из системы!
Все
книги
Нажмите на эту ссылку для входа в систему_
Все
авторы
{% extends "catalog/base.html" %}
{% Ыосk content %}
<form action="" method="post">{% csrf_token %}
{% if form.email.errors %} {{ form.email.errors }} {% endif %}
<div class="row my-2 text-center">
<div class="col-6">
<tаЫе class="taЫe taЫe-bordered my-2 text-start">
<td>
<lаЬеl>Ваш e-mail</label><br>
</td>
<td>
<р>{{ form.email }}</р>
</td>
</taЬle>
</div>
<div class="col-6"></div>
</div>
<div class="row my-2 text-start">
<div class="col-6">
<input type="suЬmit" class="btn Ьtn-primary" value="Cбpoc пароля" />
</div>
<div class="col-6"></div>
</div>
</form>
{% endЬlock %}
{% extends "catalog/base.html" %}
{% Ыосk content %}
<р>Мы отправили вам по электронной почте инструкции
по установке пароля. Если они не получены в течение
нескольких минут, то проверьте папку со спамом.</р>
{% endЫock % }
И это еще не все - теперь необходимо дать пользователю возможность ввести новый
пароль. Нажав на ссылку в полученном электронном письме, пользователь должен по
пасть на страницу сайта, где сможет сменить пароль. Чтобы предоставить ему такую
возможность, в том же каталоге \templates\registration\ создадим шаблон password_reset_
confirm.html и внесем в него код листинга 11.1О.
<tr>
<td></td>
<td><input type= "suЬmit" value=" сменить пароль " /></td>
</tr>
</tаЫе>
</foпn>
{% else %)
<hl> Сшибка при смене пароля!!! </hl>
<р> Ссыпка на сброс пароля быпа недействительной, возможно, потому, что
она уже использовалась. Пожалуйста, запросите новый сброс пароля.</р>
{% endif %)
{ % endЫock % )
{% extends "catalog/base.html" %)
{% Ыосk content %}
<hl> Пароль бып успешно изменен!</hl>
<р><а href="{% url 1 login 1 %}">Повторить вход в систему?</а></р>
{% endЫock %}
Следует также отметить, что система смены пароля требует, чтобы ваш сайт поддержи
вал работу с электронной почтой, эти настройки будут сделаны немного позже. Так что
эта часть сайта пока еще не будет работать полноценно, однако разработчик имеет воз
можность протестировать работу всех созданных шаблонов страниц. Чтобы разрешить
их тестирование, поместите в конец файла settings.py строку из листинга 11.12.
Проверим работу созданных нами шаблонов и форм. Для этого запустим наш сайт
и войдем на страницу входа пользователя http://127.0.0.1:8000/accountsЛogin/
(рис. 11.20).
0 1Z7д0.1:8000/accounts/1ogin/ Х + V
f- ➔ С (D 127.0.0.1:8000/accounts/login/
Все
книги Имя
lтестер_l
пользователя:
авторы Пароль:
1 Вход J
УтеР-ЯН nароль?
На этой странице щелкнем левой кнопкой мыши на ссылке Утерян пароль?. Вам
будет выдана страница с предложением ввести свой электронный адрес для смены
пароля (рис. 11.21 ).
0 127.0.0.1:8000/accounts/paшvc Х + V
Все
Ваш e-mail 1mupmup@mail.ru
книги
-ч+;;,;;.;.щ;
Все
авторы
Рис. 11.21. Страница ввода электронного адреса пользователя для смены пароля
Расширение возможностей администрирования сайта «Мир книг» ... 491
0 127.0.0.1:8000/accounblpasswc Х + V
� ➔ С ф 127.0.0.1:8000/aa:ounts/password_reset/d
Все
авторы
Рис. 11.22. Страница, сообщающая пользователю об отправке ему инструкции по смене пароля
Поскольку наш сайт еще не настроен на отправку электронной почты с внешнего сер
вера на реальный адрес, то в процессе тестирования работы приложения электронное
письмо со ссылкой на страницу для смены пароля будет показано в окне терминала
PyCharm (рис. 11.23).
Рис. 11.23. Инструкция для смены пароля, отправленная пользователю по электронной почте
*
Х Х
f- ➔ С ф 127.0.0.1:8000/accounts/reset/Mg/set-password/ о. � !е □ �
<
m
0 Мир книг - печатные и электронные
� интерактивные книги
Главная СГ!,.sНИЦi! о l(ОММНИИ Контакты
Пожалуйста. введите (и nодтвердите) свой новый пароль.
Все книrи
гс;:;�ь
авторы Подтвердите пароль: ==
,= ===,,----'
пароль
COpyflghtOQO"���·. 2023.&:е,Щ,,ВВ�
На этой странице введем новый пароль, его подтверждение и нажмем на кнопку Сме
нить пароль. Если все было сделано правильно, то откроется окно с сообщением
об успешной смене пароля (рис. 11.25). Нажмите в этом окне на ссылку Повторить
вход в систему?, и вы вернетесь на сайт «Мир книг».
f- ➔ С ф 127.0.0.1:8000/accounts/reset/done/
Все
книrи
Пароль был успешно изменен!
ПоВТОRИТЬ вход в систему?
Все
авторы
JI !!! 15
уктура Даннь�е Ограни- Индексы .. >�:;:;ы J[:� .,._' ____···_·· · ·_ · ·_ ·__
Пароль
- -··_ · · _···_ -·__,
• JI dЬО {SQUt• 3) 0-Т�,,ьтров.ать ···· 'J?
• � Таб111U>1 {18)
� О auth_goup id password last_login is_sц: usemame
> \Е] auth_goup_pe,missions 1 [pbkdf2_sha2565390000SelyKqMaFylslmG7aT r 1 anatoly
> [\11 auth_permission
i> jt, auth_user 2 pbkdf2_sha256S390000SбoCmВnehJwomcaVvmANW9iS 2023-01-15 О Тестер_l
:> :о) auth_usor_goups +h8eViuCvmEPdhНjrVJsRZNeSIDЬ8pSWPjZIXefwAwl= 1б:0з,02.оm10
t> lG] auth_user_user_permissions
...,
" ......_, Мир книг - печатные и электронные
&Xi
---------
интерактивные книги
Главt@я cтp..oJtiЩa О комnании KQ.!fio!ill,!
Все
книги Имя
пользовател
я:
Все
авторы Пароль: 1···..···
1 Вход 1
УтерJJН паром,?
- ■ilПllil■ 1:1ми;11
В ход
Сведения из базы данных
Книги
Рис. 11.28. Главная страница сайта после входа на нее зарегистрированного пользователя
494 Глава 11
Если теперь на данной странице набрать новый пароль и нажать на кнопку Вход, то
будет выведена главная страница сайта (рис. 11.28).
Как видно из данного рисунка, на странице нет никаких признаков того, что на ней на
ходится зарегистрированный пользователь. Кроме того, на ней нет ссылки на страницу
с идентификацией пользователя и входа в систему. Доработаем наш сайт: создадим на
главной странице сайта ссылки Вход, Выход и добавим вьmод сведений о пользовате
ле, который вошел на сайт после успешной проверки параметров входа.
G glеАккаунт
ф rn.aeкaa
(3
Аенн.�е"
•ОНФИАенцмапыt0t:ть
П1ро11ь nри.nож:ени• СО3дtн 1S:36 · 8811••с6рм-r•н•• >
121 6еюnас:;юстt1о Вход • аw.каунт ма устройстае Windows 10:58 · Ве1н111обритани.11 >
il, Настром10< достуnе
Посt-tотреrь деИС'Н)МJI, с:е•3анные с 6еюnасносrыо
е Ппат•ж:и и nодnиеk'И
0 06 al(l(arнтe
>
ко�Ф�&14Цkl.nьмос:т� YtflC>elifll.
1 nsроль ::::::> >
� Пароли приложений
Пароли приложений позволяют входить в аккаунт Google на устройствах, которые не
поддерживают двухэтапную аутентификацию Такой пароль достаточно ввести один раз.
Подробнее ....
Почта на устройстве
i
15"36 15·37
Компьютер Windows
ыбе ите п и
В р р ложение и устройство, дл которых нуж о со д т паро риложе и
я н з а ь ль п н я
.
Приложение • Устройство
:----.,,---,
Выбрать Выбрать СОЗдАТЬ
п и
р лож устройство
е ни е
IИ!шiii
Календарь
Приложение
Контакты «Почта»
VouTube
f- Пароли приложений
ваши пароли приложений
Устройство
Назеание дат. еднеrо
IPhone '8НИR
IPad
По'!та на устроitстее 15:З
Компьютер Windows BlackBerry
мае
Выберите nрипожение и устройс
Google Аккаунт ф
f- Пароли приложений
Ваши nароли приложений
После этого будет сгенерирован уникальный пароль для приложения (рис. 11.34).
Этот пароль нужно запомнить (а лучше записать), он будет использован вашим сайтом
для отправки почтовых сообщений.
Мы сделали самое сложное - выполнили настройку почтового клиента, который будет
обслуживать почтовые отправления с нашего сайта. Теперь нужно внести минималь
ные изменения в настройки нашего приложения. Открываем модуль settings.py и вносим
в него коррективы, приведенные в листинге 11. 13.
Расширение возможностей администрирования сайта «Мир книг» ... 497
инструкции
готово
Рис. 11.34. Уникальный пароль для приложений
0 127.0.0.1:8000/accounts/pass1vc, Х + V
f- ➔ С (D 127.0.0.1:8000/accounts/password_reset/
Все
книги Ваш e-mail lmupmup@mail.ru
А·Ы:Н+IФI
Все
ав1оры
Mai'-ru Почта Мой Мир Однсжла� Иrры Знакомtrеа Ноеости Поиа:: Все nрое:кты mupmup@maH.ru выход
@ mail , о наnисатъ nисьма HaclJ)OЙ•:11 о.
1:3 Входящие Письмо , преды,qущ� � ,1.
+. Оmравленные
Е1 Черновики Отвеnm, всем Переслаn, 1 Удалить I Эrо сnам J I Печаn, iПеремесmтъ в "1 �
• Архив
11 Все оп,еченные флажком Для смены пароля пользователя с зnектронной почтой mupmup@mail.ru перейдите по ссылке ниже:
http 11127.О. О 1 :8000Iaccountslreset1Мglbla62i-328945ee85a4d37Iac3e2411QaeeefeЗ/
ПРИМЕЧАНИЕ
Если вы будете использовать другие почтовые службы (mail.ru, yaпdex.ru и др.), то нужно
применять настроечные параметры именно этих служб, с которыми можно ознакомиться на
соответствующих сайтах.
Расширение возможностей администрирования сайта «Мир книг»... 499
0 Х 0 Х + v
*
121.0,1),1:8000/accounts(passw 127.0,0,1:8000/account;/reset
� ➔ С (D 127.0.0.1:8000/accounts/reset/Mg/set-pass,vord/ о, � !!:? □ �
<
I()�FПA'lli
Мир книг - печатные и электронные
� интерактивные книги
�
Все книrи Пожалуйста, введите (и подтвердите) свой новый пароль.
В се Новый пароль:
авторы Подтверди,е пароль:
F""=====s--�
Сменить пароль
{% Ыосk sidebar %)
<nav class="nav flex-colшnn">
<а class="nav-link" href="{% url 'books-list' %)">Все книги</а>
<а class="nav-link" href ="{% url 'authors-list' %)">Все авторы</а>
{% if user.is_authenticated %}
<а class="nav-link"
href="{% url 'logout' % } ?next={{request.path})">Выход</а>
<div>Boшeл: {{ user.get_username ))</div>
500 Глава 11
{% else %}
<а class= "nav-link"
href=" {% url 'login' %} ?next= { {request .path}}">Вход</а>
{% endif %}
</nav>
{% endЬlock sidebar %}
В этом коде используются теги шаблона if ...else ...enctif для условного отображения
текста в зависимости от того, является ли значение { {user.is_authenticated}} истинным.
Если пользователь аутентифицирован, то мы знаем, что это вошел зарегистрированный
пользователь, поэтому вызываем { {user.get_username}}, чтобы отобразит.ь его имя.
Затем мы создаем URL-aдpec для входа и выхода из системы, используя тег шаблона
URL-aдpeca и имена соответствующих конфигураций url. Обратите также внимание на
то, как мы добавили фрагмент ?next= { {request.path}} в конец блока url. Это означает,
что следующим URL-aдpecoм будет URL-aдpec текущей страницы. После успешного
входа пользователя в систему представления будут использовать значение next, чтобы
при выходе из системы перенаправить пользователя обратно на страницу, с которой он
входил в систему.
Протестируем то, что мы сейчас сделали. Если теперь загрузить главную страницу сай
та, то мы увидим, что на боковой панели появилась дополнительная ссылка с надписью
Вход (рис. 11.39).
Щелкните левой кнопкой мыши на ссылку Вход, и вы попадете на страницу идентифи
кации пользователя (рис. 11.40).
Введите на этой странице имя и пароль нашего тестового пользователя и нажмите на
ссылку Вход - мы опять попадем на главную страницу сайта, но при этом в боковой
панели появится имя вошедшего пользователя, а ссылка Вход будет заменена на ссыл
ку Выход (рис. 11.41).
Расширение возможностей администрирования сайта «Мир книг» ... 501
Книги
Вход Пароль:
[в�о�
У1е12ян па12оль?
• 1
г� Мир книг - печатные и электронные интерактивные'
&О книги
fлавная СТWJ:!!Ш!;\, О компании Контакты
Выход
Сведения из базы данных
Вошел: Количество книг - 5 На складе в наличии - Количество авторов - 5
Тестер_l 9
Книги
При нажатии на ссьmку Выход пользователь вернется на главную страницу сайта, при
этом имя пользователя исчезнет, а ссылка Выход изменится на ссьmку Вход.
В итоге мы реализовали возможность идентификации пользователей. Это обеспечивает
разделение всех посетителей сайта на две категории:
□ обычные пользователи - с ограничением доступа к некоторым страницам сайта;
□ зарегистрированные пользователи - с возможностью входа на страницы сайта, ко
торые недоступны для .обычных пользователей.
Такое разделение достаточно часто встречается на сайтах различного типа:
□ интернет-магазины (обычным посетителям доступен только просмотр каталога
с товарами, а заказы могут делать только зарегистрированные пользователи);
□ социальные сети (обычные посетители могут только ознакомиться с условиями раз
мещения своих страниц, а зарегистрированные пользователи могут сформировать
свои страницы, выкладывать на них информацию, общаться с другими пользовате
лями);
□ блоги (обычные посетители могут только просматривать страницы блога, а зареги
стрированные пользователи - оставлять свои отзывы) и т. п.
представив, что сайт «Мир книг» - это некий аналог электронной библиотеки для уда
ленных пользователей или площадки для продажи книг.
Начнем с того, что расширим модель Bookinstance (экземпляры книг) так, чтобы полу
чить возможность использования приложения Django Admin для оформления заказа
(выдачи) книг нашему тестовому пользователю.
Прежде всего, мы должны предоставить пользователям возможность взять книгу на
какое-то время. В модели Bookinstance уже есть поле для обозначения статуса экземпля
ра книги (status) и поле для хранения даты возврата книги (due_back), но у нас пока нет
связи между этой моделью и моделью «пользователи». Мы создадим такую связь с по
мощью поля ForeignKey («один ко многим»), т. е. «один пользователь - несколько
экземпляров книг». Кроме того, нужно будет создать простой механизм для проверки
условия, не просрочил ли пользователь возврат полученной книги.
Импортируем модель user из модели django.contrib.auth.models, которая бьmа создана
в административной панели. Для этого откроем файл catalog\models.py и добавим строку
кода (листинг 11.15) чуть ниже предыдущей строки импорта в верхней части файла
(рис. 11.42).
# экземпляр книги
class Bookinstance(models.Model):
book = models.ForeignKey('Book', on_delete=models.CASCADE, null=True)
504 Глава 11
inv_nom ; models.CharField(
max_length;2Q,
nulldfrue,
hеlр_tехt;"Введите инвентарный номер экземпляра",
vеrЬоsе_nаmе;"Инвентарный номер")
status ; models.ForeignKey('Status',
on_delete=dels.CASCADE,
nulldfrue,
hеlр_tехt;'Изменить состояние экземпляра',
verbose_nаmе;"Статус экземпляра книги")
due_back ; models.DateField(null;True,
Ыankdfrue,
hеlр_tехt;"Введите конец срока статуса",
verbose_name;"Дaтa окончания статуса")
borrower ; models.Foreig!).I<ey(User, on_delete�odels.SET NULL,
nulldfrue, Ыankdfrue,
verbose_nаmе;"Заказчик",
hеlр_tехt;'Выберите заказчика книги')
objects ; models.Manager
# Метаданные
class Meta:
ordering ; [ "due_back"]
def str (self):
return '%s %s %s' % (self.inv_nom, self.book, self.status)
Теперь добавим в эту модель свойство, которое в наших шаблонах позволит показать,
просрочен ли конкретный экземпляр книги. Хотя мы могли бы сделать такую проверку
в самом шаблоне, но использование свойства представляется более эффективным. Так
что добавим в верхнюю часть файла catalog\models.py импорт модуля для обработки дат
(листинг 11.17) и определение свойства внутри класса вookinstance (листинг 11.18).
@property
def is_overdue(self):
if self.due back and date.today() > self.due back:
return True
return False
Эти изменения сделают поле borrower видимым в разделе Admin, так что мы сможем при
необходимости назначить пользователя user для экземпляра книги вookinstance.
Теперь, когда можно оформить выдачу книги конкретному пользователю, зайдем в па
нель администратора и закрепим за нашим-тестовым пользователем несколько экземп
ляров книг в разделе Book Instances: установим тестовому пользователю значение поля
borrowed, присвоим значение status полю В заказе и назначим сроки возврата как на
будущие, так и на прошедшие даты.
Итак, запускаем наш сайт, входим на страницу административной панели с паролем
суперпользователя (см. рис. 8.31) и щелкнем левой кнопкой мыши на ссьшке Book
Instances - на открывшейся странице в таблице со списком экземпляров книг появи
лась колонка Заказчик (рис. 11.43).
Как можно видеть из данного рисунка, статус В заказе имеют две книги. Загрузим
страницу с экземпляром книги «Дубровский», имеющей статус В заказе, - на от
крьmшейся странице с информацией об этом экземпляре книги появилось новое поле:
Заказчик. В вьmадающем списке выберем для этой книги в качестве заказчика пользо
вателя с именем Тестер_! и сделаем этот заказ просроченным (выберем любую дату из
прошедшего периода). В итоге получим следующую страницу (рис. 11.44).
При нажатии на кнопку СОХРАНИТЬ будет выполнен возврат на предыдущую стра
ницу, где мы увидим внесенные нами изменения (рис. 11.45).
Проделаем ту же процедуру с другой книгой, имеющей статус В заказе, но установим
для нее дату возврата из будущего периода (рис. 11.46).
Теперь создадим представление (view) для получения списка всех книг, которые были
заказаны пользователем. На этот раз мы создадим представление на основе другого
базового класса Django - L�ginRequiredМixin. Представление (view), созданное на основе
этого класса, сможет вызвать только пользователь, который вошел в систему со своим
паролем. Мы также явно зададим имя шаблону (teщ:,late_name) вместо имени шаблона
по умолчанию. Это связано с тем, что у нас может быть несколько разных списков
���'�.:��;�-�-.,��
506 Глава 11
-·-�
IWfД •
·�..,..
Выберите book iпstaпce для изменения
- + д<>6з"ть
�•;
о """" СТАТУС� КИW'W -
., -.,, Вщ3'<00\\6--,9
д/UА-СТАtюА . ,о
-·-
8ooks + дооао,пь
о Дy6poa<:IOlii Наскл,де 8
+ДО6а8"1'Ь
о ео....к- 11рщ\3>1а Колонка
t.anguage, +ДQб<1$1ПЬ
о насклод• б
+l\06-ТЬ
PuЬli$l,en
о Змот0i1 ,._ В>гх»е
St•t- +дм=ть
о ЗОлоtой ftМtIOk на складе 4
ПОJ!ЬЗОВАТЕim "rпnnы
о 12стуrы• на складе 3
rpynnы
о 12<ту
..... На складе
9 ЬОО1< IIIS!ances
CATAl.00
Authofs +добае�ть
ll<>Oks Вооk:
+добае,m,
Status.s + Дolia&><Jb
-
Измененные
параметры Закзэчик; Тест�р_1 v
ЕФИФМ
Рис. 11.44. Выбор заказчика на конкретный экземпляр книги
Расширение возможностей администрирования сайта «Мир книг» ... 507
Деiiстеие:
о ДуброDСКИЙ На складе 8
о Войttаимир Продана 7
о Зоnотой теле11Ок
о 12стулье11 На складе з
о 12 стульеа На складе 2
о 12стулье11 На складе
о Дуброl!СКИЙ В ,аказе 9
9 Ьооk instances
Рис. 11.45. Результаты изменения поля ЗАКАЗЧИК и даты окончания статуса экземпляр книги
о 12ступье11 На складе
о 12стуnье11 На складе
о 12ступьеа На складе
о ДуброDСКНЙ В 3ЗКЗ3е
Теперь нам нужно создать шаблон для страницы, на которой будут показаны книги со
статусом В заказе. Сначала создайте файл для этого шаблона:
\templates\catalog\bookinstance_list_borrowed_user.html
Затем напишите в нем код листинга 11.22.
Этот шаблон очень похож на те, которые мы создали ранее для объектов книги (вооk) и
авторы (Author). Здесь сначала проверяется условие- есть ли заказы у данного пользо
вателя, т. е. не пустой ли список заказов { % if bookinstance_list % ) • Если список заказов
пуст, то выводится сообщение «Нет книг со статусом В ЗАКАЗЕ». Если у пользователя
есть заказы, то организуется цикл for, в котором выдается информация о заказанных
книгах - {% for bookinst in bookinstance_list %). Обратите внимание, что в теле цикла
есть инструкция if для проверки условия, не просрочен ли заказ- {% if bookinst.
is_overdue %). Если заказ окажется просроченным, то информация о нем (дата возврата
книги) будет показана красным цветом (text-danger). А название книги, которая нахо
дится в заказе, представляет собой ссылку на страницу с информацией об этой книге:
href ="{% url 'book-detail' bookinst.book.pk %)"
Для установления факта, что заказ просрочен, здесь предусмотрен метод is_overdue,
который создан в модели экземпляров книг:
{% if bookinst.is_overdue %)
Так как мы создали новую НТМL-страницу с заказами пользователя, то создадим ссыл
ку на нее. Откроем главный шаблон base.html и в блоке sidebar добавим код листин
га 11.23 (изменения выделены серым фоном).
Вход
Сведения из базы данных
Количество На складе в Количество
1 наличии - 9
книr - 5 авторов - 5
Книги
.-�··
{j([;)
_, .
.i:
-- ,
1�-
.r :•"
ии
('1 Мир книг - печатные и электронные
� интерактивные книги
Вх0д Пароль:
1 Вход 1
Xrt.� 12Ш!.1�1
Рис. 11.48. Страница сайта «Мир книг» для входа зарегистрированных пользователей
Мои заказы для этого пользователя. Если теперь щелкнуть левой кнопкой мыши на
ссылке Мои заказы, то откроется новая страница с книгами, которые заказал именно
этот пользователь (рис. 11.50). Причем книга с просроченным сроком возврата будет
выделена красным цветом.
Выход
/ Сведения из базы данных
Вошел: Тестер_l
Количество книг - 5 На с�аде в наличии - 9 Количество авторов - 5
Мои заказы
Книги
Рис. 11.49. Страница сайта «Мир книг» после входа авторизованного пользователя
Все книги
Взятые книги красным цветом
В ыход
Вошел:
Тестер_l
Мои
заказы
Рис. 11.50. Страница сайта с перечнем книг со статусом В заказе пользователя Тестер_1
Если на этой странице нажать кнопку Выход, а потом перейти на главную страницу, то
ссылка Мои заказы исчезнет, т. к. в системе будет находиться уже неавторизованный
пользователь.
512 Глава 11
Здесь у нас только одно поле для ввода имени, но форма может иметь любое количест
во элементов ввода и связанных с ними текстовых меток. Атрибут элемента type опре
деляет, виджет какого типа будет показан в той или иной строке. Атрибуты name и id
служат для однозначной идентификации поля в коде JavaScript, CSS и НТМL, в то вре
мя как value содержит значение поля, когда оно показывается в первый раз. Текстовая
метка добавляется при помощи тега label (строка с текстом Введите имя в листин
ге 11.24) и имеет атрибут for со з�ачением идентификатора id того поля, с которым
связана эта текстовая метка.
Элемент input типа type="suЬmit" будет по умолчанию показан как кнопка ОК, нажав на
которую пользователь отправляет введенные им данные на сервер (в нашем случае -
только значение поля с идентификатором team_name). Атрибуты формы action и method
определяют, каким методом будут отправлены данные на сервер (атрибут methoct) и куда
(атрибут action).
Рассмотрим более подробно два последних элемента:
□ action - это ресурс (URL-aдpec), куда будут отправлены данные для обработки.
Если значение не установлено (т. е. значением поля является пустая строка), тогда
данные будут отправлены в представление view (функцию или класс), которое сфор
мировало текущую страницу;
□ method- определяет метод отправки данных (POST или GET):
• метод POST должен использоваться тогда, когда необходимо внести изменения
в базу данных на сервере. Применение этого метода должно повысить уровень
защиты от межсайтовой подделки запроса (CSRF);
• метод GET предназначен только для форм, действия с которыми не приводят
к изменению базы данных (например, для поисковых запросов). Кроме того, этот
метод рекомендуется применять для создания внешних ссылок на ресурсы сайта.
Роль сервера в первую очередь заключается в выводе начального состояния формы
(либо содержащей пустые поля, либо с установленными начальными значениями). По
сле того как пользователь нажмет на кнопку ОК, сервер получит все данные формы
и должен провести их проверку на корректность. В том случае, если форма содержит
неверные данные, сервер должен снова отобразить пользователю форму, показав при
этом поля с правильными данными, а также сообщения о том, что нужно исправить
514 Глава 11
в полях с ошибочными данными. В тот момент, когда сервер получит запрос с пра
вильными данными, он должен выполнить все необходимые действия (например,
сохранить данные в БД, вернуть результат поиска, загрузить файлы и т. п.) и при необ
ходимости проинформировать пользователя об успешном завершении операции.
Как видите, создание НТМL-формы, проверка и возврат данных, перерисовка введен
ных значений, а также выполнение желаемых действий с правильными данными может
потребовать весьма больших усилий, чтобы все это «заработало». Django делает этот
процесс намного проще, беря на себя создание некоторых «тяжелых» и повторяющихся
фрагментов кода.
Веб-браузер Сервер
Вернуп, пользователю
заполненную форму
Создание
формы с
Пользователь данными
заполняет или пОJIЬЗо вателя н
обновляет форму сообщением об
ошибках
Получение
запроса
Запрос
пользователя на
получение формы
�JJ:;::;
п�
Страница с Оrправка в браузер
сообщенне.ч об URL-aдpec-a страницы В�олн�е Да
успешном с сообщением об денстввис
завершеннн верными данными
дейсrвнй вьmОJПiенни действий
БД
сведения об авторе. Здесь нам пока еще не потребуются формы Django, а сведения об
авторах получим из модели.
Для начала создадим представление (view), которое будет обрабатывать запросы поль
зователей. Откроем файл WebBooks/catalog/views.py и напишем в нем код листинга 11.25.
Это очень простое представление. Здесь создается объект author, в который из БД за
гружаются сведения обо всех авторах. Этот объект упаковьmается в словарь context,
который затем передается в шаблон edit_authors.html.
Создадим теперь в каталоге World_Books\WebBooks\templates\catalog\ файл с именем edit_
authors.html и напишем в нем код листинга 11.26.
(% extends "catalog/base.html" %}
(% Ыосk content %}
<div class="row text-start lh-2">
<h5>Сnисок авторов для редактирования</h5>
</div>
<div class="row">
<div class="col-2 "></div>
<а href="/authors_add/((authors_add}}">Дoбaвить автора</а>
<div class="col-8 ">
<tаЫе class="taЫe taЫe-striped taЫe-bordered text-start">
<thead>
<tr>
<th>Id</th>
<th>Имя</th>
<th>Фамилия</th>
<th>Редактировать</th>
</tr>
</thead>
<tbody>
(% if author %}
(% for author in author.all %}
<tr>
<td>((author.id))</td>
<td>{{author.first_name}}</td>
<td>{{author.last_name}}</td>
<td><a href="/edit_author/{{author.id}}">Измeнить</a> ,
<а href="/delete/{{author.id}}">Yдaлить</a></td>
</tr>
Расширение возможностей администрирования сайта «Мир книг» ... 517
{% endfor %)
{% else %)
<р> В базе данных нет авторов</р>
{% endif %)
<tbody>
</tаЫе>
</div>
<div class="col-2"></div>
</div>
{% endЫock %)
Эта ссылка добавлена в боковую панель базового шаблона в блок, к которому имеют
доступ только зарегистрированные пользователи. Таким образом, ссылка на страницу
с редактированием сведений об авторах откроется только тогда, когда зарегистриро
ванный пользователь войдет в систему.
Протестируем работу сайта после внесенных изменений. При запуске сервера
открьmается главная страница сайта. После регистрации пользователя в системе в меню
боковой панели появится ссылка на страницу для редактирования данных об авторах
(рис. 11.53).
Если теперь щелкнуть левой кнопкой мьШiи по данной ссылке, то откроется страница
со списком авторов (рис. 11.54).
Как видно из данного рисунка, перед шапкой таблицы находится ссылка Добавить ав
тора, а в каждой строке две ссылки: Изменить -изменить (отредактировать) сведения
об авторе, Удалить -удалить данные об авторе из БД. Пока эти ссылки не работают,
т. к. не созданы соответствующие страницы. Создадим формы, с помощью которых
зарегистрированные пользователи смогут добавлять, редактировать и удалять сведения
об авторах книг, и начнем с формы для страницы Добавить автора.
Поскольку каждая форма определяется в виде отдельного класса, который расширяет
базовый класс forms. Form, то создадим в каталоге World_Books\WebBooks\catalog\ файл с име
нем forms.py (рис. 11.55).
В этом модуле напишем код формы для добавления в БД новых авторов (лис
тинг 11.29).
Расширение возможностей администрирования сайта «Мир книг» ... 519
Все
авторы
Мои
заказы
Рис. 11.53. Ссылка на страницу редактирования данных об авторах
..
r;&Xi...... Мир книг - печатные и электронные
интерактивные книги
Воше
л: 2 Александр Пушкин ',, И�менить,
Тестер_! Удалить
Редаl<Тор
3 Лев Толстой Изменит�,.
авторов
Удалить
Мои
4 Илья Ильф И;,менит�.
заказы
Уд алить
□ about - сведения об авторе, имеет тип foпns.CharField. Так как это поле предна
значено для ввода многостраничного текста, то для него сменили виджет
(widget=foпns. Textarea);
□ photo - поле для ввода фото (портрета) автора. Данное поле предназначено для вво-
да изображений, поэтому оно имеет тип foпns. ImageField.
Затем в файл views.py добавим следующий код для вызова страницы, где пользователь
сможет добавить нового автора, - это будет функция с именем authors_add() (лис
тинг 11.30).
ния, которые пользователь ввел в поля формы, а затем на их основе создается специ
альный объект ( obj), который записьmается в БД ( obj.save). После этого с помощью
функции reverse вызьmается страница со списком авторов (authors-list).
ПРИМЕЧАНИЕ
Обратите внимание на строку, в которой создается объект form: form = Form_add_
author(request.POST, request.FILES). Так как в форме вводится изображение, то здесь
обязательно должен присутствовать параметр request. FILES. При его отсутствии файл
с изображением не будет передаваться и не будет записан в папку media/images/.
{% extends "catalog/base.html" %)
{% Ыосk content %)
<h5>Добавить в БД автора книги</h5>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %)
<div class="row">
<div class="col-2 "></div>
<div class="col-8 ">
<tаЫе class="taЬle text-start">
{ { form ) )
</tаЫе>
</div>
<div class="col-2"></div>
</div>
Расширение возможностей администрирования сайта «Мир книг» ... 523
В первой строке этого кода мы подключили базовый шаблон base.html. Затем в блоке
content создана таблица, в которую и вьmодится наша форма - { { form } }.
ПРИМЕЧАНИЕ
В данном шаблоне обратите внимание на тег, в котором создается форма <form:
action='"' method="POST" ct ti а t/ о at >. Так как в форме вводится изо
бражение, то здесь обязательно должен присутствовать параметр en t e= "multiQart/'
orm-data'. При его отсутствии файл с изображением не будет передаваться и не будет за-
писан в папку media/images/.
Создавать ссылку для вызова этого шаблона не нужно, т. к. мы это сделали ранее
в шаблоне edit_authors.html. Если вернуться к фрагменту кода это страницы, то в приведен
ном далее фрагменте кода строка с соответствующей ссьmкой выделена серым фоном:
{% extends "catalog/base.html" %}
{% Ыосk content %}
<div class="row text-start lh-2">
<h5>Сnисок авторов для редактирования</h5>
</div>
<div class="row">
<div class="col-2 "></div>
а href=" aut ors а
<div class="col-8 ">
<tаЫе class="taЫe taЫe-striped taЬle-bordered text-start">
А вот создать маршрут для вызова шаблона authors_add.html необходимо. Для этого
открываем модуль World_Books\WebBooks\catalog\urls.py и добавляем в него строку из лис
тинга 11.32 (изменения вьщелены серым фоном).
Итак, у нас все готово для вывода на экран формы для добавления авторов в БД. Запус
тим наше приложение и загрузим главную страницу сайта. Пройдем регистрацию для
того, чтобы появилась возможность выполнять редактирование сведений об авторах.
Теперь по открьmшейся ссылке Редактор авторов перейдем на страницу редактирова
ния сведений об авторах (рис. 1 1.57).
Если все было сделано правильно, то при переходе по этой ссылке будет загружена
форма для добавления в БД нового автора (рис. 1 1.58).
Как видно из данного рисунка, модули Django, используя теги разметки фреймворка
Bootstrap� сгенерировали НТМL-страницу со всеми необходимыми атрибутами:
□ метки и поля для ввод� текстовой информации («Имя автора», Фамилия автора»);
□ календарь для выбора даты;
□ широкое поле для ввода многостраничного текста («Сведения об авторе»);
□ кнопку для выбора файла с фотографией (портретом) автора;
□ кнопку для сохранения данных.
Заполним поля формы необходимыми данными и нажмем кнопку Сохранить. После
этого пользователь будет переадресован на страницу со сведениями об авторах, на
которой появятся обновленные данные (рис. 11.59).
Теперь реализуем процедуру удаления записи об авторе из БД. Для этого не нужно соз
давать новую форму, достаточно создать соответствующее представление (view).
Откроем файл views.py и напишем в нем код для удаления из БД сведений об авторах
(листинг 11.33).
Расширение возможностей администрирования сайта «Мир книг» ... 525
'Ф
'
Мир книг - печатные и электронные
интерактивные книги
�lд!!iЩlil QmмnaHl'!!I �
Все Добавить в БД автора книги
книrи
Имя
1 !
Все автора:
авторы ФаМИJ'IИЯ
Выход автора:
Вошел:
Тестер_!
Дата i1в.01.202з □1
рождения:
Редактор
СвеАения
авторов
об автор-е:
Мои
заказы
/,,
f Сохранить 1
1 Copyrisht()OQ��---Fbfll)all38ЩНЩIНW
Рис. 11.58. Форма для добавления в БД новых авторов книг
Все
авторы
C,HH!IF
Выход
Вошел:
Тестер_l
6012.ис_Зверксш
.,;:;;:;;;;
Редактор
авторов·
Мои
заказы .,;.;;;;;;;
« ПeRJШ![l�дl!JдWi!.1! Crp. 2 иэ 2.
# удаление авторов из БД
def delete(request, id):
try:
author = Author.objects.get(id=id)
author.delete()
return HttpResponseRedirect("/edit_authors/")
except:
return HttpResponseNotFound("<h2>Автор не найден</h2>")
Создавать ссьшку для вызова функции удаления автора не нужно, т. к. мы это сделали
ранее в шаблоне edit_authors.html. Если вернуться к фрагменту кода этой страницы, то
в приведенном далее фрагменте кода строка с соответствующей ссылкой выделена
серым фоном:
<tbody>
{% if author %}
{% for author in author.all %}
<tr>
<td>{{author.id}}</td>
<td>{{author.first_name}}</td>
<td>{{author.last_name}}</td>
<td><a href="/edit_author/{{author.id}}">Измeнить</a> ,
author. id) ">У cl:>i
</tr>
{% endfor %}
{% else %}
<р> В базе данных нет авторов</р>
{% endif %}
<tbody>
А вот создать маршрут для вызова функции удаления автора из БД необходимо. Для
этого открьmаем модуль World_Books\WebBooks\catalog\urls.py и добавляем в него строку из
листинга 11.34 (изменения вьщелены серым фоном).
path('authors/<int:pk>/', views.AuthorDetailView.as_view(),
name='authors-detail'),
path('aЬout/' , views.aЬout, name='aЬout' ),
path('contact/', views.contact, name='contact'),
path('mybooks/', views.LoanedBooksByUserListView.as_view(),
name='my-borrowed'),
path('edit_authors/', views.edit_authors, name='edit_authors'),
path('authors_add/', views.add_author, name='authors_add'),
path('delete/<int:id>/', views.delete, name='delete'),
Здесь при вызове функции delete в нее в виде целого числа передается идентификатор
той записи в БД, которую нужно удалить (<int:id>). Теперь при нажатии левой кнопки
мыши на ссьшке Удалить в одной из строк таблицы со сведениями об авторах инфор
мация об авторе будет удалена из БД (рис. 11.60).
F'J:!liRli
Мир книг - печатные и электронные
80
':-�
интерактивные книги
�;�.Р{кgмании К<тw�цы
Все Список авторов для редактирования
книги Добавить автоt,о
авторы Александр
1 Беляев Изменить,
Выход Удалить
Открываем файл views.py, пишем в нем код для изменения в БД сведений об авторах
(листинг 11.35).
{% extends "catalog/base.html" %)
{% Ыосk content %}
<div class="row text-start lh-2">
<hЗ>Изменить сведения об авторе</hЗ>
</div>
<form method="post" enctype="multipart/form-data">
{% csrf_token %}
<tаЫе class="text-start">
{% for field in form %}
<tr>
<th>{ { field.laЬel_tag }}
{{ field.errors ))
</th>
<th>{ { field )}</th>
</tr>
{% endfor %)
<th>
<button type="suЬmit">Coxpaнить</button>
</th>
530 Глава 11
</tаЫе>
</foпn>
{% endЫock %}
А вот создать маршрут для вызова функции изменения сведений об авторе необходимо.
Для этого открываем модуль World_Books\WebBooks\cataloglurls.py и добавляем в него строку
из листинга 11.38 (изменения выделены серым фоном).
Здесь при вызове функции edit_author в нее в виде целого числа передается идентифи
катор той записи в Бд, которую нужно отредактировать ( <int: ict>).
Итак, у нас все готово для вывода на экран формы для изменения сведений об авторе.
Запустим наше приложение и загрузим главную страницу сайта. Пройдем регистрацию
для того, чтобы появилась возможность редактировать сведения об авторах. Теперь
по открьmшейся ссылке Редактор авторов перейдем на страницу редактирования све
дений об авторах (рис. 11.61).
Если все было сделано правильно, то при переходе по ссылке Изменить будет загру
жена форма для редактирования сведений об авторе (рис. 11.62).
Как видно из рис. 11.62, форма не является пустой, она заполнена информацией об
авторе, которая загружена из БД. Обратите внимание на поле Фото автора, на данной
форме сама фотография не отображается, но содержится ссылка на нее, которая имеет
синий цвет. Если щелкнуть левой кнопкой мыши по данной ссылке, то откроется окно
с полноформатным изображением (рис. 11.63).
В поле title на вкладке показан истинный размер изображения, а сама фотография
адаптирована под размер окна браузера. При изменении размера окна браузера размер
изображения также будет меняться, сохраняя пропорции.
Итак, мы реализовали весь функционал сайта, связанного с добавлением, удалением и
корректировкой данных об авторах на основе форм Django. Теперь создадим аналогич
ные формы для корректировки данных о книгах.
532 Глава 11
пг-m
Все
Имя автора: !Борис
!зверков
1
Фамилия автора:
авторы
Дата рождения: j16.01.1953
0 ..,,.,.,.,,,. �,м,1191 х +
� t O ф Ш.О.О.1'8000/.,,..W�""°"-)"9 Е1. 15 * () �
Это очень простое представление. Здесь создается объект book, в который из БД загру
жаются сведения обо всех книгах. Этот объект упаковьmается в словарь context, кото
рый затем передается в шаблон edit_books.html.
Создадим теперь в каталоге World_Books\WebBooks\templates\catalog\ файл с именем edit_
books.html и напишем в нем код листинга 11.40.
{% extends "catalog/base.html" %}
(% Ыосk content %}
<div class="row text-start lh-2">
<h5>Сnисок книг для редактирования</h5>
</div>
534 Глава 11
<div class="row">
<div class="col-2 "></div>
<а href="{% url 'book_create' %}">Добавить книгу</а>
<div class="col-8 ">
<tаЫе class="taЫe taЬle-striped taЫe-bordered text-start">
<thead>
<tr>
<th>Id</th>
<th>Название книги</th>
<th>Редактировать</th>
</tr>
</thead>
<tbody>
{% if book %}
{% for book in book.all %}
<tr>
<td>{ {book.id}}</td>
<td>{{book.title}}</td>
<td><a href="/book/update/{{book.id}}">Измeнить</a> ,
<а href="/book/delete/{{book.id}}">Yдaлить</a></td>
</tr>
{% endfor %}
{% else %}
<р> В базе данных нет книг</р>
{% endif %}
<tbody>
</tаЫе>
</div>
<div class="col-2"></div>
</div>
{% endЫock %}
Эта ссылка добавлена в боковую панель базового шаблона в блок, к которому имеют
доступ только зарегистрированные пользователи. Таким образом, ссылка на страницу
с редактированием сведений о книгах откроется только тогда, когда зарегистрирован
ный пользователь войдет в систему.
Протестируем работу сайта после внесенных изменений. После запуска сервера
открывается главная страница сайта. Вслед за регистрацией пользователя в системе
536 Глава 11
пиm
t Мир книг - печатные и электронные интерактивные
книги
�
Все авторь,
Выход
Вошел: Тестер_l
На складе в наличии - 9 Количество авторов - 7
Редактор
авторов Книги
Редактор
книг
Мои
заказы
(."!I ип,
Мир книг - печатные и электронные интерактивные
книги
�
[J\ilВtlilaст� окомnамт, Контакты
Все книги Список книг для редактирования
Добавить книгх
Все
ld Название книrи Редактировать
авторы
Мои
зак.азы
Как видно из данного рисунка, перед шапкой таблицы находится ссылка Добавить
книгу, а в каждой строке таблицы две ссылки: Изменить - изменить (отредактиро
вать) сведения о книге и Удалить - удалить данные о книге из БД. ПЬка эти ссылки
не работают, т. к. не созданы соответствующие страницы. Создадим форму, с помощью
которой зарегистрированные пользователи смогут добавлять, редактировать и удалять
сведения о книгах. Когда форма создается на основе базового класса мoctelForm(), то по
требуется всего одна форма, как для добавления новой книги, так и для редактирования
книги, которая уже занесена в БД. Для удаления книги из БД форма не нужна, посколь
ку в этом случае новая информация в БД не вводится.
Начнем реализацию формы для работы с книгами с создания класса BookМodelForm() на
основе базового класса ModelForm(). Для этого откроем файл forms.py и добавим в него код
листинга 11 .43.
Здесь выполнен импорт модели данных вооk. Затем создан класс вookМodelForm на основе
базового класса ModelForm(). В теле этого класса объявлен встроенный класс Meta, в ко
тором создан объект model на основе модели данных вооk. Затем создан объект fields
с указанием тех полей модели, которые будут отображаться на форме. В данном случае
на форме будут отображаться все поля из модели данных.
Для каждого поля модели вы можете определить значения меток, виджетов, текстов
сообщений об ошибках и т. д., если они не были заданы в модели. Их можно переопре
делить в классе меtа при помощи словаря, содержащего поле, которое требуется изме
нить, и его новые параметры. В качестве примера приведем синтаксис кода, который
мы могли бы использовать для изменения параметров поля для ввода аннотации к кни
ге (листинг 11.44).
fields = [ 'about', ]
labels = { 'aЬout': ('Аннотация'), }
help_texts = { 'about': ('Не более 1000 символов') , ]
страница уже встречалась нам в административной части сайта, когда вводили данные
о книгах от имени главного администратора сайта.
Создадим сразу три представления (view) для ввода сведений о новой книге, для обнов
ления сведений о книге и для удаления книги из БД. Откройте файл WebBooks\
catalog\views.py и добавьте в него код листинга 11.45.
Здесь на основе базовых классов (createView, UpdateView, DeleteView) созданы три пользо
вательских класса:
□ для ввода в БД данных о новой книге- BookCreate() ;
□ для обновления в БД сведений о книге- вookUpdate() ;
□ для удаления книги из БД- BookDelete().
Каждый класс связан с моделью данных (вооk).
Для классов вookCreate() и вookUpdate() мы определили показываемые на форме поля
(fields). Здесь можно было применить тот же синтаксис, что и для класса ModelForm()
(перечислить все необходимые поля в виде списка), но мы подключили к форме все
поля модели данных при помощи инструкции fields = '_all_'. При этом если необхо
димо, то вместо fields можно воспользоваться атрибутом exclude (от англ. исключить),
чтобы определить поля модели, которые не нужно включать в форму. Здесь также
можно указать начальные значения для каждого поля, применяя словарь пар «иw,_поля/
значение».
Расширение возможностей администрирования сайта ((Мир книг» ... 539
{% extends "catalog/base.html" %}
{% Ыосk content %)
<form action="" method="post" enctype="multipart/form-data">
{% csrf_token %)
<tаЫе class="text-start">
{{ form.as_taЫe }}
</tаЫе>
<input type="suЬmit" vаluе="Сохранить" />
</form>
{% endЬlock %)
Код этого шаблона напоминает наши предыдущие формы и прорисовку полей при по
мощи таблицы. Заметьте, что мы снова указали выражение {% csrf_token %}. Кроме того,
следует отметить, что код шаблона для класса ModelForm() короче и проще, чем код шаб
лона для класса Form().
ПРИМЕЧАНИЕ
В данном шаблоне обратите внимание на тег, в котором создается форма <form:
action="" method="POST" engtyp�multip� t/:f; da а">. Так как в Ф_орме вводится изо
_
бражение, то здесь обязательно должен присутствовать параметр enctype="multjpartt
f,0,rm-dat�". При его отсутствии файл с изображением не будет передаваться и не будет за
писан в папку media/images/.
540 Глава 11
{% extends "catalog/base.html" %)
{% Ыосk content %)
<hl>Удаление книги</hl>
<р> Вы уверены, что хотите удалить книгу: {{ book ))?</р>
<form action="" method="POST" enctype="multipart/form-data">
{% csrf_token %)
<input type="suЬmit" action="" value="Дa, удалить" />
</form>
{% endЬlock %)
urlpatterns = [
path('', views.index, name='index'),
path('books/', views.BookListView.as_view(), name='books-list'),
path('books/<int:pk>/', views.BookDetailView.as_view(),
name='book-detail'),
path('authors/', views.AuthorListView.as_view(), name='authors-list'),
path('authors/<int:pk>/', views.AuthorDetailView.as_view(),
name='authors-detail'),
path('aЬout/', views.aЬout, name='aЬout'),
path('contact/', views.contact, name='contact'),
path('mybooks/', views.LoanedBooksByUserListView.as_view(),
name='my-borrowed'),
path('edit_authors/', views.edit_authors, name='edit_authors'),
path('authors_add/', views.add_author, name='authors_add'),
path('delete/<int:id>/', views.delete, name='delete'),
path('edit_author/<int:id>/', views.edit_author, name='edit_author'),
path('edit_books/', views.edit_books, name='edit_books'),
/ о as_ ame= 'book_create'),
/ , okU view(),
р
/ >{', views.BookDelete.as_view(),
Здесь нет ничего нового! Как можно видеть, представления (view) являются классами,
поэтому они должны вызываться через метод .as_view(). Шаблоны URL-aдpecoв для
Расширение возможностей администрирования сайта ((Мир книг» ... 541
каждого случая также должны быть вам понятны. Когда поступает запрос book/create/
(ввести сведения о новой книге), то мы просто обращаемся к представлению
views.BookCreate. Когда же поступает запрос на обновление сведений о книге, которая
уже занесена в БД (views.BookUpdate), или об удалении конкретной книги (views.
вookDelete), то мы обязаны использовать первичный ключ этой книги в БД (pk) , чтобы
выполнить соответствующую операцию именно с этой книгой.
Итак, у нас все готово для редактирования информации о книгах. Запустим наше при
ложение и загрузим главную страницу сайта. Пройдем регистрацию для того, чтобы
появилась возможность выполнять редактирование сведений о книгах. Теперь по от
крьmшейся ссылке Редактор книг перейдем на страницу редактирования сведений
о книгах (рис. 11.66).
tиищ
Мир книг - печатные и электронные интерактивные
книги
�
ГлавtЩЯ CТP-Ш:IJWili о )«)МrtЗНИИ Контакты
Все книги Список книг для редактирования
Добавить книгх
Все Ссылка на страницу
Id Название книrи Редактироватъ добаме:ния ноsой
авторы книги
Теперь все ссьmки на данной странице являются рабочими. Если щелкнуть левой кноп
кой мыши на ссылке Добавить книгу, то откроется форма с пустыми полями для ввода
сведений о книге (рис. 11.67).
Введем данные о новой книге и нажмем кнопку Сохранить. После этого пользователь
будет возвращен на страницу с редактированием данных о книгах. На ней уже будет
отображена информация о новой книге (рис. 11.68).
Как видно из данного рисунка, после добавления новой книги пользователь возвраща
ется на ту же страницу.
Если теперь щелкнуть левой кнопкой мыши на ссьmке Изменить, то откроется форма
с заполненными полями для редактирования сведений о книге (рис. 11.69).
542 Глава 11
8owe11: Тюер_l
1.......� · .,1
Swб.рмте 11""� �снмrм
Jla1,11111>111rм:
�,аор 1········· "1
.tаторое Вw�рите иэдпtlll,(fl!O
АнНО1'8ЦМ11 IIНMtll:
ISIN кммrм:
Цq1(ру6.):
SJ<!AWlt цену ttннrн
и10"р.же11н•
.. ,.
OvAOМIJtlt:'-·
j
Bwбep11nt Ф•йn I Фii\д ке 11.wб РJн
-'""-'---'""---'-'
Ваеднrе иэобраение обJtо:ци
ICoфtwип.l
Рис. 11.67. Страница сайта для ввода в БД информации о новой книге
Как видно из рис. 11.69, это не пустая форма, в нее автоматически загружаются все
данные о книге из БД. Обратите внимание на поле Изображение обложки. На данной
форме сама обложка не отображается, но содержится ссьшка на нее, которая имеет
синий цвет. Если щелкнуть левой кнопкой мьпnи по данной ссылке, то откроется окно
с полноформатным изображением обложки (рис. 11.70).
В поле title на вкладке показан истинный размер изображения, а само изображение
адаптировано под размер окна браузера. При изменении размера окна браузера размер
изображения также будет меняться, сохраняя пропорции.
Если щелкнуть левой кнопкой мьпnи рядом с какой-либо из книг на ссьшке Удалить,
то откроется форма, в которой будут присутствовать название выбранной книги и
кнопка с надписью Да, удалить (рис. 11.71).
Расширение возможностей администрирования сайта «Мир книг» ... 543
1
.О
,.� Мир книг - печатные и электронные
интерактивные книги
�it 'О1!1'>""""'1111 �
авторь� 12 стульев
1 Из,..ентъ.
Выход Удi!.!!!Ш,
•=ро•
И-П,,ьm�о:
l>одактор Выбериrе �цател.стю
ГOAИJAIHИJI: 1202э
ве.дmе rод ищнн•
1
Редактор
<киr И,1,ф
1
lиктерзm.в,юе ЦНфроео<! noco&ie no
оо-юеам "'°'""
nporpauuиpoeaмltA
l>flhon а первую очерць
nредмJэ�чемо А/111 н�ч.,.наюw.»Х
Аннотация кни,и:
nроrраммщтоs, кorop.;t решw:м
ознаКОМИТЬСR с осноеа ц:и Python с нулА.
lsoo,oo
А"""""' <ОД�рж,t!, 13 .:и,uюлсв
0 ИЭK_Python_ZIOk21jpg (599xi Х
+
f- ➔ С (D 127.0.0.1:8000/media/images/ИЭ... (:;'\. LВ * □ �
Все книги
Удаление книги
Все Вы уверены, что хотите удалить книгу: Основы программирования на Python
авторы (интерактивное ЦJ'lфровое пособие).?
Редактор
книr
Мои
заказы
Если здесь щелкнуть левой кнопкой мыши кнопку Да, удалить, то сведения о книге
будут удалены из Бд, и пользователь вернется на страницу со списком редактируемых
книг.
Итак, мы создали все страницы нашего учебного сайта.
В предыдущих главах были созданы формы сайта «Мир книг», его общий интерфейс,
главная страница, а также страницы для ввода, редактирования и удаления данных из
БД со стороны удаленного пользователя.
Теперь, когда мы создали и протестировали свой сайт, необходимо развернуть его на
публичном веб-сервере, чтобы он стал доступен через Интернет удаленным пользова
телям. Эта глава дает общее представление о том, каким образом подойти к поиску
хостинга для размещения сайта, что нужно сделать, чтобы разметить свой сайт на пуб
личном сервере.
Мы рассмотрим здесь следующие вопросы:
□ как подготовить инфраструктуру сайта перед его публикацией в сети Интернет;
□ как выбрать хостинг-провайдера для своего сайта;
□ как зарегистрировать аккаунт на сайте хостинг-провайдера;
□ как создать виртуальное окружение для размещения сайта на публичном сервере;
□ какие изменения нужно внести в параметры настройки веб-приложения;
□ как развернуть сайт на хостинге timeweb.
В этом разделе сделан обзор мероприятий по выбору хостинга, описан процесс подго
товки сайта к публичному размещению, а также приведен практический пример раз
мещения сайта «Мир книг» на хостинге timeweb.
может так случиться, что самым важным элементом при выборе услуг хостинrа станет
возможность масштабирования.
В настоящее время при выборе зарубежных серверных площадок существует риск быть
отключенным от сервиса. В связи с этим предпочтительнее размещать веб-сайты на
серверных площадках отечественных компаний. Среди российских компаний можно
выделить следующих хостинr-провайдеров: AdminVPS, Тimeweb, Sprinthost, Beget.ru,
REG.RU и ряд других. В данной книге в качестве примера будет показана публикация
сайта на серверах компании Timeweb.
Хостинг timeweb работает более 10 лет, поэтому специалисты компетентны и уверены
в своих знаниях. Сервис обеспечивает высокую скорость и максимальную стабильность
работы сайтов своих клиентов благодаря современному оборудованию, ПО и про
граммным системам. Для удобства пользователей администрация разработала собст
венную панель управления. Она хорошо структурирована, а навигация интуитивно по
нятна. Это отечественная компания с головным офисом в Санкт-Петербурге. Еще одно
преимущество использования российского хостинга - поддержка со стороны сервер
ной службы на русском языке. У пользователя есть возможность позвонить в сервис
ную службу (звонок по России бесплатный из любого региона) или получить ответы на
все необходимые вопросы через чат непосредственно на сайте компании. Обычно хос
тинг-провайдеры предоставляют следующий набор услуг: VPS, выделенные серверы,
готовые решения.
□ VPS (виртуальный частный сервер)- это аренда виртуального сервера с возможно
стью администрирования самим клиентам. Клиент получает полную свободу в на
стройке сервера. Ему предоставляется rооt-доступ, а значит, он может устанавливать
любое ПО, редактировать ресурсы, настраивать бэкапы, создавать FТР-аккаунты
и др.
□ Выделенные серверы - это идеальный вариант для высоконагруженных интернет
магазинов, игровых серверов, порталов, у которых высокая посещаемость. Они
обеспечивают самую большую производительность и стабильность, а также полную
независимость от соседей.
□ Готовые решения - в данном случае предлагается пропустить настройку сервера
и приступить к запуску проекта, используя один из предварительно собранных ком
панией образов. Можно запустить сервер с одной из таких ОС в один клик: UЬuntu,
Fedora, Windows. Также есть возможность запуска сервера со следующими прило
жениями: MySQL, Django. Для начинающих разработчиков предпочтительнее имен
но этот вариант хостинrа. Следует отметить, что на хостинге timeweb в течение
1 О дней можно без оплаты протестировать работу сайта.
провайдеров, и они, конечно же, будут отличаться от тех настроек, которые были на
этапе разработки сайта.
Критически важны следующие настройки файла settings.py:
□ DEBUG - этот параметр при развертывании сайта должен быть установлен в False
(DEBUG = False). В результате прекратится вьmод важной отладочной информации;
□ SECRET_KEY- это большое случайное число, применяемое для защиты от CSRF (важ
но, чтобы ключ не указьmался в исходном коде и/или не запрашивался с другого
сервера). Django рекомендует размещать значение ключа либо в переменной окру
жения, либо в файле с доступом только для чтения.
Указанную настройку SECRET_KEY можно установить с помощью кода листинга 12.1.
Можно изменить приложение таким образом, чтобы читать SECRET_КЕУ и DEBUG из пере
менных окружения, если те определены, или в противном случае задать для них значе
ния по умолчанию.
Для этого в файле \WebBooks\settings.py можно закомментировать значение SECRET_кЕУ
и добавить новые строки, выделенные в листинге 12.2 серым фоном и полужирным
шрифтом.
Значение DEBUG будет тrue по умолчанию и станет False в том случае, если переменная
окружения DJANGO_DEBUG будет проинициализирована пустой строкой, т. е. когда
DJANGO DEBUG = ' '.
ПРИМЕЧАНИЕ
Было бы понятнее, если мы могли просто установить для DJANGO_DEBUG значение True или
False напрямую, а не использовать «любую строку» или «пустую строку» (соответственно).
К сожалению, значения переменных среды хранятся как строки Python, и единственной
строкой, которая распознается как False, является пустая строка (например: ьооl (' ') ==
False).
Мы перед развертыванием сайта не будем менять эти параметры, т. к. они могут нам
пригодиться в этом виде при отладке работы сайта после развертьmания на сервере.
Однако их можно изменить уже после того, как сайт будет успешно запущен на сер
верной площадке.
timeweb>
Бесплатно по России
Больше, чем
хостинr 8 (800) 700-10-81
Здесь можно выбрать любой вариант. Однако рекомендуется опция Optimo+, которая
дает возможность развернуть до 1 О сайтов. Это нам пригодится, т. к. в процессе работы
нам действительно придется создать как минимум три сайта:
Публикация сайта в сети Интернет 553
Y�ar+ Optimo+
Идеальное решение для сайт,,..-----� Выбор популярных б11оrеров и
визитки сайтов-rа11ерей
Оптима льный
вариант
После выбора типа хостинга вам будет предложена ст�аница регистрации аккаунта
пользователя (рис. 12.3).
Здесь достаточно ввести ФИО и электронный адрес. Несмотря на подсказку, что ввод
номера телефона не обязателен, данное поле нужно заполнить, т. к. это все равно при
дется сделать после того, как вам откроют доступ на сервер. После нажатия на кноп
ку Зарегистрироваться вам на почту придет уведомление с логином и паролем
(рис. 12.4).
После нажатия на кнопку Войти в панель управления вы будете сразу направлены на
страницу своего личного кабинета. Здесь для начала можно познакомиться с порядком
дальнейшей работы. Для этого в верхнем правом углу нужно выбрать опцию С чего
начать работу (рис. 12.5).
После выбора этой опции откроется окно подсказки (рис. 12.6).
Здесь будет предложено три варианта:
□ создать новый сайт;
□ перенести сайт с другого хоста;
□ разместить файлы сайта с другого компьютера.
554 Глава 12
Реrистрация
(')
Фl!J.Jll<ЦO Юр.№ЩО
10151S х
о JIO�)CQOJJ>mWЩOфep!Oi\ИдaIOCClrAIOteka
oбpa6ouynE$)((.1f<il!w,;i,Q(,l\a/;WЬIX
timeweb>
БОЛЬШЕ, ЧЕМ ХОСТИНГ
Добро пожаловать в
TimeweЫ
Baw аккаунт готов к работе
Логин: cq95650
Пароnь: elxn8poVq,2zt
доступ по FTP
fJQ.l/vh314Jimeweb.ru
Логин и пароль для панели уnравnения 11 FTP совпадают
)С
Поздравляем!
Ваш аккаунт готов к работе.
Сайты Исгt011ьзсззм
Уст-.� смs
Резервные коnии
Продвижение
Ускоритмь сай-rое
@ Домены V
,. (осчозl-!О� саi\т)
(D Файпоеый менеджер РНР7.1-Руто<: М·НТТР
в Почта
Просмотреть код
Теперь посмотрим структуру папок этого сайта и найдем, где находится главная стра
ница. Для этого открьmаем вкладку Файловый менеджер, находим директорию
Основной сайт и открьmаем в нем папку с именем puЫic_html. В этой папке будет всего
один файл с именем index.html (рис. 12.1О).
Здесь puЫic_html - это корневая папка, в которой находятся все файлы сайта. Поскольку
это простейший одностраничный сайт, то в данной папке находится всего один файл
с главной страницей - index.html.
Убедимся, что это страница именно того сайта, который был создан по умолчанию.
Двойным щелчком мыши откроем данную страницу и внесем небольшие изменения
в ее код в тег <body> сразу после тега <center> (рис. 12.11).
Публикация сайта в сети Интернет 557
timeweb>
IIOl1ЬWi:. ЧЕМ ХОСТ\4ИГ.
Здравстsуйте!
8ilu .�ц.унт в «тайм8,б. rюдrот- • р,боте.
лоrмн 11 ri.PQnь дл:�1 ехода в na><enь }111JiM- ОТ11Ро8116!1,1 � .;л� nочтv, которую еы �ли nри
P�(ТJ),i!Ji<I!.
Эт. страница (ЩДзна аатомаПNКЮ1 енкте t а1<Хаумтом, eaw сайт щкет дооУПек norne эarpyam фаwюе ка
{еl)!Щ).
Дополнительно:
s;nooOO!Wыii uem }:!;aVJ:!! \;!Jособы оnпаты �!!!t lli!дд.�
Дисковое про
Файловый менеджер
(о�
S Почта
Файл Правка Архиватор Сортировать:
� Еmаil•рассылки
t С 1t /puЬlic__html
® Реклама на Яндексе Домашняя
Имя файла/директории Ра.эмер
cgi-bln 700
Базы данных
-0-
Е) index.htm 8.52Кб 600
Инструменты
Чтобы добавить файлы, перетащите их в это окно.
@J Аккаунт
index.htm
45 }
46
47 p.line
48 border-top: lpx solid #dbdbdb; Т�кст, добааnt!нный на
4� } домаwн1Оtо страницу сайта
1
50 </style>
51 </head>
52
53 <bodyl}.>:_.-----------:;z�,...r:::;,.____
_
54 centeг>
S5 Этот текст был добаален нtt домаwнкао страницу СilЙта
и �-
image: url(http: //timeweb. c<>fll/ru/img/gradi,ent. jpg); background-repeat: repeat-x; background-align: top; ">
57
53 <tr>
59 <td style&"height :148px;width: 240рх; • valign•"bottom" align "right"><img 2
Сохранить
О Для корректноrо отображе+<ия и редактироеания файnое е кодироеках,
отличных от код ироеки Unicode, используйте FТР-клиеwт.
Нажмем кнопку Сохранить и закроем данное окно. Если теперь снова открыть наш
сайт по ссьmке, которая создана по умолчанию, то мы увидим на главной странице сай
та внесенные нами изменения (рис. 12.12).
В результате этих действий мы узнали следующее:
□ все файлы сайта располагаются в папке puЫic_html;
□ в этой папке находится главная страница сайта index.html.
0 Хосmнr·nровайдер TimeWeb,n Х +
Д Не защищено I cq95650.twl.ru !В
Текст, доба1111енный на
timeweb>
домаwн10t0 страницу callтa
Здравствуйте!
ваш аЮ<аунт в «ТаймВэб» подготовлен к работе.
Лоп,,н и пароль для входа в панель управления отправлены на электронную почту, которую вы ук
регистра�и.
Так как у сайтов на Django более сложная структура папок, да еще дополнительные
фреймворки и библиотеки, то мы не будем использовать данный шаблон, а создадим
пустую директорию и с нуля начнем формировать в ней наш будущий сайт.
Статус сервисов
/,, Web •
е MySOL •
Открытие
FТР
доступа по
SSH
•
lifl Почта
iii SSH С)
f- ➔ с i webconsole.timeweb.ru
х +
-.,•,ebconso!e.time'l•1eb.ru
Создать
Сайты новый сайт
Установка CMS
Список созданных сайтов
Резервные копии
х
Создать новый сайт
Выбрать Выбрать
После этого появится окно выбора типа создаваемого сайта (рис. 12.18).
Здесь вам будет предложено три варианта:
□ создать сайт на основе CMS;
□ создать сайт на основе конструктора сайтов;
□ создать новую директорию.
Поскольку наш сайт уже разработан и нам его нужно просто перенести на серверную
площадку, то мы выбираем опцию Создать новую директорию. После этого откроется
окно для ввода имени создаваемой директории (рис. 12.19).
Имя директщ,им:
Комментарий к сайту:
Создать
Вводим имя нашего сайта «newsite» и нажимаем кнопку Создать. После того как за
вершится процесс формирования пустой папки-шаблона, в списке созданных сайтов
появится новый сайт с именем «newsite» (рис. 12.20).
Проверяем, включен ли доступ к удаленному серверу по протоколу SSH (рис. 12.21).
Если вы уже открьmали такой доступ, то переключатель должен остаться во включен
ном состоянии. Если по каким-либо причинам он выключен, то переведите его во
включенное состояние.
Теперь нужно сделать контрольное подключение к нашему новому сайту, созданному
на удаленном сервере. Для этого вызьmаем вкладку Инструменты и открьmаем SSН
консоль (рис. 12.22).
Публикация сайта в сети Интернет 563
·•
сайт
А w.ь • л WеЬ •
8 МySOL. • 1З MySOL •
::.��
!. FТР •
С8
SSH (8 ii SSH С)
� Инструменты
SSН-консоль
Ctontab
После этого должно появиться терминальное окно, которое подключено к вашему но
вому сайту на удаленном сервере (рис. 12.23).
Проверяем структуру папок, к которым мы имеем доступ. Пишем в окне терминала
команду для просмотра содержимого папки:
~$ ls
Мы увидим две папки, которые созданы в шаблоне нашего нового сайта: newsite и
puЫic_html (рис. 12.24).
564 Глава 12
i webconsole.timeweb.ru
/ -1-. 1 1-1 11 / / ! /
7 // 7 -,-\/ - ) 11 11 / - ) \
1_1 1_1_1_1_1\_!l_ll_l\_/_._1
Тhе progra111S 1nc1uded w1th the Ubuntu system are free software;
the exact distr1bution teгms for each program are descr1bed 1n the
1nd1v1dual files 1n /usr/share/doc/*/copyr1ght.
Ubuntu comes with AВSOLUТELY NO WARRANТY, to the extent permitted Ьу
арр11саЫе law.
се 522S9f<Jvh314: $
;g Сайты л
\.�. бесплатно
Резервные коn"и
Безопасность сайтов
os Commerce (2.З.4 PrestaShop (1
бесnлатно бесплатно
РШТд\iU?
Magento (1.9.З 9)
бесплатно
Django 241•
Djaлgo. свободный фреймворк Д/!Я ве6-nриложений на языке Python, использующий шаблон проектирования MVC. Сайт на
Django строится из одного или нескольких приложений, которые рекомендуется делать отчуждаемыми и подключаемыми. Это
одно из существенных архитектурных отличий зтоrо фреймворка. Для работы с базой данных Dja1190 использует собственный
ORM, в котором модель данных описывается классами Python, и по ней генерируется схема базы данных. Для работы с Dja1190
необходимы общие представления о том, что такое серверное ве6-nроrраммирование и ве6-фреймворки. Рекомендуется базовое
понимание концепций программирования и языка Python.
Если теперь щелкнуть левой кнопкой мыши по ссылке Django, то откроется окно
с предложением установить данное приложение (рис. 12.26).
Нажимаем на кнопку Установить приложение и ждем завершения данного процесса.
После этого открываем вкладку Сайты и выбираем опцию Мои сайты. В списке соз
данных сайтов появится новый сайт, в имени которого будет ключевое слово «Django»
(рис. 12.27).
но
Новый сайт д�ннм
нaDjaneo ИМII
" django_n86bo
РНР 7.4• Python З.4 • НТТР
Как видно из рис. 12.27, был создан новый сайт и для него сгенерировано имя «django_
n86bo»·. Кроме того, создано временное доменное имя «cc52289-django-n86bo.twl.ru».
Это доменное имя будет существовать в течение десяти дней. Обратите внимание на
привязку доменных имен: у сайта на Django есть временное доменное имя, а у нашего
сайта «newsite» нет временного доменного имени. Отвяжем временное доменное имя от
сайта «django_n86bo» и привяжем его к нашему новому сайту «newsite». Для смены
привязки доменных имен воспользуемся соответствующими ссылками (рис. 12.28).
Сначала отвязываем доменное имя от сайта «django_n86bo», для этого активируем
ссылку Отвязать домен. Потом привязываем освободившееся доменное имя к нашему
сайту через ссылку Привязать домен (рис. 12.29).
Публикация сайта в сети Интернет 567
После этих действий наш новый сайт с именем «newsite» получит временное доменное
имя (рис. 12.30).
Как видно из рис. 12.30, временное доменное имя теперь привязано к нашему сайту
«newsite», и его можно будет использовать для проверки работы сайта в Сети. Пока мы
сделали первый шаг, в результате которого:
□ на удаленном сервере создана папка newsite, в которой мы развернем наш сайт;
□ к нашему сайту привязано временное доменное имя, которое в течение 1 О дней
позволяет отлаживать сайт.
Посмотрим, действительно ли проект WebBooks был создан. Для этого в окне термина
ла выполним команду просмотра структуры папок:
~$ 1s
После этого в окне терминала мы должны получить сообщение о том, что проект
успешно создан (рис. 12.32).
L:ebBooks/WebВooks
j Со3дан проект ,•
Фа�:iл Правка Архиватор Сор
t С 1't /newsiie/puЫic_html/WebBooks/WebBooks
0 _ini1_.py ОБ
0 asgi_py 393 Б
0 settings_py 3.25 Кб
0 uiis.py 750 Б
0 1vsgi ру 393 Б
Файловый менеджер
Файл !lр_авка Арх1,1ват,ор
Архив ровать
и
Разархивир
Имя файnаfдиректор/ овать
Запаковать и скачать
_русас!ю_
иви овать
Загрузить и разарх р
@ _iniL.py
Options +ExecCGI
AddDefaultCharset utf-8 AddНandler wsgi-script.py
RewriteEngine 0n
RewriteCond %{REQUEST_FILENAМE} !-f
RewriteRule л{.*)$ /wsgi.py/$1 [QSA,L]
Публикация сайта в сети Интернет 571
Файловый менеджер .
V Правка
.htaccess
1 Options +ExecCGI
2 AddDef11.ultCh11rset utf-8
З AddH11ndler wsgi-script .ру
4 RewriteEngine On
5 R�riteCond i{REQUEST_FILENAМE} !-f
б RewriteRule А(.")$ sitel/wsgi.py/$1 [QSA,L)
7
Рис. 12.35. Код файла .htaccess сайта Django
Здесь мы фактически указали путь к файлу wsgi.py. Именно по этому пути он находится
в папках нашего проекта WebBooks. Нажимаем кнопку Сохранить и закрьmаем данное
окно. В файловом менеджере можно проверить, что файл wsgi.py находится именно там,
где требуется (рис. 12.36).
Файловый менеджер
Фаiiл Правка Архиватор
18 _pycache_
Рис. 12.36. Место расположения
файла wsgi.py
@ _iniL.py
@ asgi.py
Затем в этой же папке находим файл settings.py, открываем его и вносим следующие
минимальные изменения. В самом начале этого модуля добавляем импорт дополни
тельного пакета (листинг 12.5, изменения выделены серым фоном).
J1иcmlнr1U. Измененныiкод.фdnа........,,
J:!!P.Qrt os
from pathlib import Path
572 Глава 12
Находим строку ALLOWED-HOSTS [ J и меняем ее, как показано в листинге 12.6 (измене-
ния выделены серым фоном).
Здесь необходимо указать используемое доменное имя (или список допустимых до
менных имен). На период отладки мы вместо имени поставили звездочку, означающую,
что данный сайт допускает использование любых доменных имен. Когда реальное до
менное имя будет получено и зарегистрировано, этот параметр можно будет поменять.
Нам осталось отредактировать содержимое файла wsgi.py, который находится в этой же
папке. Что должно содержаться в данном файле, мы снова можем подсмотреть на сайте
Django, который был создан на основе шаблона CMS (в нашем случае это сайт с име
нем «django_n86bo»). Переходим на данный сайт, заходим в папку puЫic_html/site1, от
крьmаем файл с именем wsgi.py. Он будет содержать следующий код (рис. 12.37).
V
Файловый менеджер
V Файл .Правк,а f\рхив.атор
wsgi.py
В этом файле нужно будет изменить четыре строки. Копируем код этого файла в буфер.
Открываем аналогичный файл wsgi.py на нашем сайте, удаляем содержимое этого файла
и вставляем код из буфера. Теперь корректируем этот файл, как показано в листин
ге 12.7 (изменения выделены серым фоном).
Публикация сайта в сети Интернет 573
wsgi.py
django-n86bo.twl.ru) или открыть эту ссьmку в новой вкладке браузера, то должна за
грузиться административная панель Django (рис. 12.39).
Если вы увидели подобную картину, то это значит, что все действия на предыдущих
этапах выполнены правильно. Теперь можно перейти к следующему этапу - переносу
вашего сайта с рабочего компьютера на удаленный сервер.
django
View release notes for Django З.2
Django Documentation
Topics, references, & how-to's
Рис. 12.39. Административная панель Django при активации временного доменного имени
ре, они могут подключиться анонимно. Еще один протокол - SSH - служит для безопас
ной передачи, шифрующей (скрывающей) логин и пароль, а также содержимое файла.
Т
Доступ по FР
IP
176.57.210.144 �
Хост
11:с..-_.:....--==-----========' j!! Откnючить сетеаой диск...
Открыть общий доауn к пталоrу...
vh314.timeweb.ru \!,}
Закрыть общий АОСJУЛ к каталоrу...
Логин Показать ресурсы администратора
сс52289 �
Имвсоеl:t'Нl!НМя;
�[;Порт):
�===================:
!D
/176.57210.144
1Е] SSUТLS [ � соq1ем �ль-� Eillilil)
lчё1t1ая sаnмсь: сс522&9
[!.ароль:
ВНИМАНИЕ: �,ъ здесь пароль небе3ооасно!
1Е\ Исnоnь:юеа,ъ гn--.il rщ,оль для sащм1Ъ1 napon11
Удi!J)ённый каталог:
!}окапьньil каталог:
� Пассмвны\ режим обмена �ак WеЬ-браузер)
□ Иаюnь:юеа,ъ бран� или nрокс:м-сервер
[0nредели1Ъ НОВЬIЙ... •11 Измени,ъ ..
После этого откроется окно, в котором будут две панели (рис. 12.43).
Как видно из рис. 12.43, в левой панели открыты папки с нашим проектом WebBooks на
удаленном сервере, а в правой панели открываем папку с проектом WebBooks на
локальном компьютере, где велась разработка проекта.
--..:;...---:-----
п
-.._..._ �---
Па ка с
-----<(
Папка с
....---- проектом на
;о_Кб и, 236 Кб, фай�_<:��0- се ве О Кб и, 236 Кб, файлов: О из 3, пап
проектом на
.,.____.__.....,;.;:.__===-===' компьютере
·\PycharmProjects\World_booкs\WebBooкs>
FЗ Просмотр I F4 Правка I F5 Копирование! Fб Перемещение! F7 Каталог i F8 Удаление I Alt+F4 Выход
Файловый менеджер
Файл Правка
Файловый менеджер
1' С tlt /newsite/puЫic_html/WebBooks
Файл Правка • Архиватор
Им.я ф,айпа/директории
1' С 1't /newsite/puЫic_html
WebBooks
Им• файла/д11ре<Т◊РИИ л
WebBooks
l
catalog
;\
media
___j�1 cgi-Ыn
Старое
положение static Новое
static положение
@ .htaccess
templates
@ .htaccess_old
@ db.sqliteЗ
@ manage.py
Как видно из данного рисунка, папку static нужно поднять на один уровень вверх (все
вложенные папки с их содержимым тоже должны переместиться).
Осталось внести некоторые изменения в файл WebBooks/WebBooks/settings.py. Открываем
данный файл на удаленном сервере и меняем строки листинга 12.8 (изменения выделе
ны серым фоном).
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
Указываем новый путь к папке static и путь к медиафайлам (листинг 12.10, изменения
выделены серым фоном).
В конце файла добавляем строки листинга 12.11 (изменения выделены серым фоном).
DEFAULT_AUTO_FIELD = 'django.dЬ.models.BigAutoField'
# Переадре ����= аницу сайт
LOGIN-REDI - =
# настройки отправки e-mail
''' это пробная
# EМAIL_BACKEND ас psole.EmailBackeщ!'
альна .
EМAIL_ВАСКЕNО = ___ ke . . • ==== nci'
EМAIL_HOST = 'smtp.gmail.com'
# EМAIL_USE_T
EМAIL_USE_SSL = True # ДЛЯ отправки с .1
EМAIL PORT = 465
EМAIL_HOST_USER = "postoHtl952@9I11oil.com"
EМAIL HOST PASSWORD =
Публикация сайта в сети Интернет 579
Вход
Сведения из базы данных
Количество книг - 6 На складе в наличии - 9 Количество авторов - 7
Книги
Аленсандр
Пушкин
Если ваша страница загрузилась, значит, можно оплачивать услуги хостинга, регистри
ровать доменное имя и заменить временное доменное имя на постоянное.
@�
-.._. _______,,>,
7 8ведиrе название дом"на .ru
,rr.::::'_
�ьдомен
__.,,.,,..
Мои домены
SSL-сертификаты
timeweb> 60ЛЬШЕ,
Чl!МХОСТИНГ.
заработал через 4 часа). По истечении некоторого времени сайт станет доступен поль
зователям сети Интернет.
Итак, мы вьmолнили все шаги от проектирования сайта до развертьmания его в Интер
нете. Теперь учебный сайт, разработанный в данной книге, можно будет посмотреть по
адресу putbook.ru.
Зарегистрироаанное
" django_n86bo Домены не n;жвязг:ны ДОМ�ННО!' ИМЯ
PtiP7.4-Python 3.4 · НПР
В предыдущих главах был создан сайт «Мир книг» с использованием СУБД SQLite, его
общий интерфейс, главная страница, а также страницы для ввода, редактирования и
удаления данных из БД со стороны удаленного пользователя.
Теперь, когда мы поработали с «легкой» СУБД SQLite, нужно научиться создавать сай
ты на основе более мощных СУБД, таких как MySQL или PostgreSQL, т. к. именно эти
СУБД чаще всего применяются на публичных серверах. В этой главе подробно описа
ны все шаги, от разработки сайта на локальном компьютере до его развертывания
на публичном сервере с использованием MySQL. Мы рассмотрим здесь следующие
вопросы:
□ как выбрать СУБД перед публикацией сайта в Интернете;
□ как установить сервер MySQL на локальный компьютер;
□ как создать базу данных на MySQL на локальном компьютере и подключить к ней
проект Django;
□ как сформировать инфраструктуру на удаленном сервере для развертывания сайта
Django с СУБД MySQL;
□ как создать базу данных MySQL на удаленном сервере;
□ как перенести сайт с локального компьютера на публичный сервер.
Создать новую БД можно двумя способами: через панель SCHEМAS или через панель
инструментов главного меню.
Для того чтобы создать новую БД через панель SCHEМAS, нужно в области этой
панели со списком БД щелкнуть правой кнопкой мыши, и в контекстном меню выбрать
опцию Create Schema (рис. 13.1 ).
11 МySQL WorkЬeлch
----------
� Fяrer obJects
Load SpatiaJ Data Рис. 13.1. Создание новой базы
данных через панель SHEMAS
Set as Default Schema
Filter to This Schema
Создать новую
базу данных
Create Schema...
Alter Schemit...
Для того чтобы создать новую БД через панель инструментов, нужно в области этой
панели щелкнуть левой кнопкой мыши на значке, обозначающем добавление новой БД
(рис. 13.2).
О Server Status
1
!, Client Connections
В обоих случаях после этих действий появится вкладка, в которой нужно ввести имя
новой БД и указать параметры сортировки. В данном случае для примера база данных
будет названа book_db. Параметры сортировки можно либо выбрать из выпадающего
списка, либо оставить те, которые предлагаются по умолчанию. В нашем примере
оставлены параметры по умолчанию (рис. 13.3).
586 Глава 13
О Server status
! Rename References 1
,!! Client Connections
.1. Users and Privileges Charset/Collation: [Defu!At Charse\ •] 1Default Collal:iol •]
� statш and System VariaЫes
& Data Export
� Data lmport/Restore
Затем нужно нажать на кнопку Apply, которая находится в нижней части этой вкладки.
В результате откроется окно с текстом скрипта, который создаст новую БД. При необ
ходимости скрипт можно отредактировать прямо в этом окне (рис. 13.4).
OnlineDDl
дlgoritnm: Default LockType: Default
В верхней части окна имеется область Online DDL, предназначенная для установки
параметров выполнения скрипта. Эти параметры могут быть полезны при манипуляци
ях с уже существующей БД. При создании новой БД рекомендуется оставить эти зна
чения по умолчанию (Default). При нажатии на кнопку Apply откроется новое окно,
в котором будет предложено вьmолнить данный скрипт (рис. 13.5).
После нажатия на кнопку Finish база данных будет создана. В левой панели на вкладке
SCHEМAS появится информация о созданной базе данных (рис. 13.6).
Приложения Django и MySQL 587
The following tasks wi/1 now Ье executed. �ase monitor lhe exea,tion.
Press Show logs to see the execuЬon logs.
Пока в данной базе нет таблиц, представлений, хранимых процедур и самих данных.
Все это будем создавать позже средствами Django. Если в процессе работы над проек
том потребуется подключение к нашей (или другой) БД, то это можно сделать из меню,
выбрав опции Database -> Connect to Database (рис. 13.7).
После этого откроется окно, в котором нужно ввести имя базы данных и нажать на
кнопку ОК (рис. 13.8).
Итак, база данных создана, теперь можно перейти к проекту Django.
588 Глава 13
Подмючение
кБД
Clrl+U
Migration Wizard...
�11>0.ЬЬ-
Нoslname: localhost Port: 3306 Name or IP address of the server host - and
TCP/!Pport
1
Password: Тhе user's password. W111 Ье requested later ifit's
1 . Store in Villit .. . . ] 1 . аеа,� notset.
DATAВASES = {
'default':
'ENGINE': 'django.dЬ.backends.mysql',
'NАМЕ': 'book_dЬ',
'USER': 'root',
'PASSWORD': '12344321',
'HOST': 'localhost',
'PORT' : '3306',
После этого можно создать суперпользователя базы данных, выполнив в окне термина
ла PyCharm команду:
python manage.py createsuperuser
► · auth_ыroup
► 11 auth_group Рис. 13.9. Таблицы приложения
► fiJ auth_permis catalog в БД MySQL
►Ш auth_user
► im auth_user_group
► 11 auth_user_user_p
► catalog_status
► 11 catalog_puЬlisher
► 111 catalog_language
►Ш catalog_genre
► ·, catalog_boolcinslira
► 111 catalog_book-'aulnor
► 111 catalog_Ьook
► Ш1 catalog_author
►
► 111 djanga_cantent_type
► 111 django_migrations
► 111 django_session
Если все было сделано правильно, то должен открыться наш сайт (рис. 13.10).
Приложения Django и MySQL 591
•z,nto:rt11
Мир книг - печатные и электронные интерактивные
.z
[�
книги
Книги
Количество посещении данноii страниць, • З
Как видно из рис. 13.10, база данных пустая. В ней нет сведений ни об авторах, ни
о книгах, которые мы вносили ранее, т. к. в процессе миграции создаются только таб
лицы, а данные не переносятся. Теперь можно переносить сайт на хостинг уже с базой
данных на MySQL.
Для создания нового сайта открываем вкладку Сайты и выбираем опцию Мои сайты.
После этого появится окно выбора типа создаваемого сайта. Поскольку наш сайт уже
разработан, и нам его нужно просто перенести на публичный сервер, мы выбираем
опцию Создать новую директорию. В открывшемся окне вводим имя нашего сайта
«newsite_sql» и нажимаем кнопу Создать. После того как завершится процесс форми
рования пустой папки-шаблона, в списке созданных сайтов появится новый сайт с име
нем newsite_sql (рис. 13.11).
11ewsite cc52289-_ojango-n86bo.tw1 -�
РНР 7.4 -Python 3.4 - НТТР putbш�_k.ru
Новый сайте
Как видно из данного рисунка, у нового сайта нет привязанного доменного имени, а
значит, мы не сможем проверить его работу через Интернет. Однако у нас есть свобод
ные имена доменов второго уровня, которые можем подключить. Отвязьmаем доменное
имя cc52289-django-n86bo.twl.ru от сайта newsite и привязываем его к новому сайту
newsite_sql (рис. 13.12).
newsite putbook.ru
РНР 7.4 · PythonЗ.4 · НТТР
Временный
домен
django_n8бbo Дома-�ы t-fe nривя3аны
РНР 7.4 · Python 34 - НТТР
Здравствуйте!
ваш аккаунт в «ТаймВэб» подготовлен к работе.
ЛОГ\о\н и пароль дпя входа в панель управления отправлены на электронную почту, которую вы указали при
регистрации.
Эта страница создана автоматически вместе с аккаунтом, ваш сайт станет доступен после загрузки файпов на
сервер.
Подробно о том, как размесmть сайт, в нашем mравочном центре.
Если у вашего сайта пока что нет имени, зареr:исrрируйте его. Если домен уже есть. Qet}eнeotтe к нам.
Д11с овоеnро
Файловый менеджер
Файл _Правка �рхиватор Сортировать:
t с
Размер Права
Проект D1an10
WebВooks
Имя ф.WebBooks , ,.,.�.
айnа/директории • · · .. ) 700
В этом файле нужно указать путь к модулю wsgi.py для того, чтобы перенаправлять за
просы пользователя к этому модулю. Копируем код этого файла в буфер и затем встав
ляем его в аналогичный файл нашего проекта. Теперь файл .htaccess на сайте newsite_sql
будет содержать код листинга 13.2.
Options +ExecCGI
AddНandler wsgi-script .ру
AddDefaultCharset utf-8
RewriteEngine On
RewriteCond %{REQUEST_FILENAМE) !-f
RewriteRule л(.*)$ /WeЬBooks/WebBooks/wsgi.py/$1 [QSA,PT,L]
Здесь мы фактически указали путь к файлу wsgi.py. Именно по этому пути он находится
в папках нашего проекта WebBooks. Нажимаем кнопку Сохранить и закрьmаем данное
окно. В файловом менеджере можно проверить, что файл wsgi.py находится именно по
этому пути (рис. 13.16).
Затем в этой же папке находим файл settings.py, открываем его и вносим минимальные
коррективы (листинг 13.3, изменения выделены серым фоном).
�rt os
from pathlib irnport Path
Файловый менеджер
+ с
_pycache_
Рис. 13.16. Место расположения
файла wsgi.py
@ _init_.py
@ asgi.py
@ settings.py
@ urls.py
• wsgi.py
ALLOWED_HOSTS = ["*"]
Здесь необходимо указать доменное имя (или список допустимых доменных имен). На
период отладки мы вместо доменного имени поставили звездочку, это означает, что
данный сайт допускает использование любых доменных имен. Когда реальное домен
ное имя будет получено и зарегистрировано, этот параметр можно будет поменять.
Нам осталось отредактировать содержимое файла wsgi.py, который находится в этой же
папке. Что должно содержаться в данном файле, мы снова можем подсмотреть в сайте
Django, который бьm создан в предьщущей главе (в нашем случае это сайт с именем
newsite). Переходим на данный сайт, заходим в папку newsite/puЫic_html/WebBooks/WebBooks/,
в которой открываем файл с именем wsgi.py. Он будет содержать код листинга 13.5.
l л�нr
13.&. Код фама wsgLpy cma news1te
# -*- coding: utf-8 -*
iTTport os
iTTport sys
iTTport platform
# путь в проекте к модулю rnanage.py
sys.path.insert(O, '/home/c/cc52289/- _w_s1·�·t-�/puЫic_html/WebBooks')
pe
# путь в проекте к модулю settings.py
sys.path.insert(O, '/home/c/cc52289/, ews[t /puЬlic_html/WebBooks/WebBooks')
Приложения Django и MySQL 597
В этом файле нужно будет изменить три строки (выделено серым фоном). Копируем
код файла в буфер. На нашем сайте newsite_sql открываем аналогичный файл wsgi.py,
удаляем его содержимое и вставляем код из буфера. Теперь корректируем этот файл,
как показано в листинге 13.6 (изменения выделены серым фоном).
Пробный япусксакта •·
РР'fГОМ бра- по ссыл�
cc52289-,djan,.,..n86Ьo.twl.ru
Рис. 13.17. Административная панель Django при активации временного доменного имени
cd newsite_sql
cd puЫic_html
cd WebBooks
Вот теперь, находясь в папке проекта Django с именем WebBooks (той, где содержится
скрипт manage.py), создадим приложение catalog. Для этого выполним следующую
команду:
python manage.py startapp catalog
После этого в проекте появится новая папка с именем catalog, в которой будут находить
ся все модули этого приложения (рис. 13.18).
Этот проект теперь нужно добавить в список установленных приложений, как и модуль
django_cleanup, который у нас используется для очистки хранилища медиафайлов. Для
этого открываем файл settings.py и в раздел INSTALLED_APPS добавляем две строки (лис
тинг 13.7, изменения выделены серым фоном)
INSTALLED_APPS; [
'django.contrib.admin',
'django.contrib.auth',
Приложения Django и MySQL 599
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'catalog',
'aj ango_с eanup' ,.
Файловый менеджер
Файл Правка Архиватор
t С 1t /newsite_sqVpuЫjcJ1t!:f11/WebBooks
ИмR файла/д,11�ктории
ПрИЛОЖl!НИI!
catalo&
WebBooks
catalog
@ manage,py
�' Даwборд
Базы данных MySQL Со.эдэни�
g Сайты V
ноаой БД
1о Файловый менеджер
®
T•n Точt<и дРСТуnа к ба,� данных
Реклама на Яндексе
MySQL 5.7 localhost
§ + Добави,ь_досiуn
Рис. 13.19. Вкладка Базы данных MySQL в панели управления хостинга timeweb
У нас и сайт, и база данных находятся на одном сервере. Для локального подключения
к базе данных потребуются следующие реквизиты:
□ cepвep- localhost (или 127.0.0.1);
□ имя базы данных- оно отображено на панели управления Базы данных;
□ имя пользователя - совпадает с именем базы данных;
□ пароль - формируется при создании базы данных.
Пароль можно посмотреть в конфигурационном файле settings.py сайта, который бьm
создан на основе CMS, либо изменить в разделе Базы данных, щелкнув мышью на
значке шестеренки в строке с именем БД (рис. 13.20).
Настройки:сс52289_n86Ьо
Новый пароль:
Комментарий к БД:
Сохранить
Войти в phpMyAdmin
Логик: сс52289_n8бЬо
Пароль:
Войти
Как видно из рис. 13.24, на сервере localhost создана база данных сс55289_n86bo.
Для подключения к этой БД можно задать следующие параметры:
□ имя сервера - localhost;
□ имя базы данных - сс55289_n86bo;
□ имя пользователя - сс55289_n86bo;
□ пароль - указывался при смене пароля.
Мы можем подсмотреть параметры подключения к данной БД на сайте django_
n86bo, который был создан на основе CMS. В файловом менеджере открьmаем данный
сайт и находим там файл settings.py. В коде этого файла находим словарь DATABASES
(рис. 13.25).
602 Глава 13
ь
phpMyAdmin
" Струrтура , /Jj SQL ; � nо,к• 1 Эоnроо no .,.бl>o,ty
�-��1$t0
"- 1136р,-
Содержит Cl!080.
.....JIIO'AP
щgr
...
_pltll!Jмions
L.i.! Теб1)11Щ1 •
••
СТ\!
д.�111!1!
....,_...;
�
...,__ __
NЬ�-.Jll'НJPJ
.,.._.,..._log
�
О auth_group
О aцtЬ_group_pennl,.sions
О auth_permlaslon *
!!)Обэор !ИJСтру,тура ,, 1юио(
!it � О Уда"""-
OYдa
rnm,
••* rэ063ор
..._�_typt'
:Jt ..._......... О autЬ_ustr k С1МtУР• ,.tП°""" ic ikr"""1'Ь @О<,ж:nт. OY
№\UТI>
iJI!. ..._... О autЬ_uиr_groups [j О6оо!> Ис,руnп,.а <,tflQl!CX j..Вtra»m. tfO-П,,,, ОУдаnкn,
•*
mm.
О autЬ_usar_uso,_permisslons /j Обоор rk: Clpyaypa "ПОIЮС ;. Вета...... ltO..umщ. 0Yдo
•"-
nim.
'"°"""
0 django_admln_log [!Оооор 1,1! СтРl'"'У!>• �no.
.. j,ёl!t't••- ()u,cnm, OYдa
Файловый менеджер
V
settings.py
75
76 OATAВASES = {
77 'default': {
78 'EN61NE' : 'django .db. backends. mysql', # Add 'post
79 'NАМЕ': 'сс52289_n8БЬо',
80 'USER': ''сс52289_n8бЬо',
81 'PASSWORO': 'vfti9myi',
82 }
8 3}
Копируем в буфер обмена этот код. Затем открываем файл settings.py нашего нового сай
та newsite_sql и добавляем код листинга 13.8 (изменения выделены серым фоном).
DATAВASES = {
'default': {
'ENGINE': 'django.dЬ.backends.sqliteЗ',
'NАМЕ': ВASE_DIR / 'dЬ.sqliteЗ',
DATAВASES • {
'default':
'ENGINE': 'django.dЬ.backends.mysql', i Add 'mysql'
'NАМЕ': 'сс52289_n86Ьо',
'USER': 'сс52289_n86Ьо',
'PASSWORD': 'здесь_ваш�пароль',
111
Доступ no FТР
IP
176.57.210.144 �
Логин
сс52289 ©
Qароль: ' -
сс5228З
Удйлёtн.ill каталог:
[lокальны�'! к21таnог:
� П11СО!1!1НЬi11 режим обмена 9<21К WеЬ'6раузер)
!EJ Иаюль�Тh брандмауэр И/М nрокси'СерВер
После этого откроется окно, в котором будут две панели (рис. 13.29).
Как видно из данного рисунка, в левой панели открыты папки с нашим проектом
WebBooks на удаленном сервере, а в правой панели открьmаем папку с проектом
WebBooks на локальном компьютере, где велась разработка проекта.
Приложения Django и MySQL 605
• •
д;;,;61
<Папка>
<Папка> 27.01.202315:39 -700
<Папка> 27.01.202312:50 -700 <Папка> 26.01.2023 09:1 9 •···
ру 664 27.01.202312:05 -Лl <Попка> 25.01.202318:35 ---
< Папка> 25.01.202308:43 ---
<Попка> 25.01.202318:40 ----
json О 26.01.2023 08:50 ·•··
json 114 485 26.01.202308:04 -•--
ру б8б 2 5.01.202316:48 ·•--
сэ -
тера на удаленный сервер. На этом процесс переноса файлов нашего сайта с локального
компьютера на сервер завершен.
Теперь нужно снова вернуться к файловому менеджеру личного кабинета на сайте
timeweb и перенести папку static в другую директорию. На нашем локальном компьюте
ре эта папка находилась по пути WebBooks/static. На удаленном сервере она должна нахо
диться в папке newsite/puЫic_html/static. Копируем папку static в директории newsite/puЫic_html/
WebBooks/static и вставляем ее в директорию newsite/puЫic_html/static. Это изменение проде
монстрировано на рис. 13.30.
Файловый менеджер
Файл _llравка
Файловый менеджер
Файл Пра131<а Ар)(Ива-rор
t С 1t /11��s_rt_e/p':)Ьlic:_�trnl/WeЬBooks
Имя фоЙ11о/Д11ректорим
WebBooks
111 WebBooks
c:atalog
111 cgi-Ьin
media
static
static
@ .htзccess
templates
@ .htaccess_old
@ db.sqliteЗ
@ manage.py
Как видно из данного рисунка, папку static нужно поднять на один уровень вверх (все
вложенные папки с их содержимым тоже должны переместиться).
Осталось внести некоторые изменения в файл WebBooks/WebBooks/settings.py. Открываем
данный файл на удаленном сервере и меняем строI<И листинга 13.9 (изменения выделе
ны серым фоном).
INSTALLED_APPS = [
'django.contriЬ.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
Приложения Django и MySQL 607
IГЕМР�1.'Р,,
.. Г.&R.....
=.._, .o""...
s •=,..�-=""·
TEMPLATES = [
{
'BACKEND': 'django.ternplate.backends.django.DjangoTernplates',
'DIRS': [ • DIR·;] ,
'APP_DIRS': True,
'OPТIONS': {
'context_yrocessors':
'django.ternplate.context_yrocessors.debug',
'django.ternplate.context_yrocessors.request',
'django.contrib.auth.context_yrocessors.auth',
'django.contrib.messages.context_yrocessors.messages',
],
},
},
Указьmаем новые пути к папке static и медиафайлам (листинг 13.11, изменения выде
лены серым фоном).
'/static/'
В конце файла добавляем строки листинга 13.12 (изменения выделены серым фоном).
DEFAULT_AUТO_FIELD = 'django.dЬ.models.BigAutoField'
--
�-,,-c.-rna!:!!:!!& сайт nосле--хо-а--в --"'
�;;;;;:;�����:::::��
ilБackencfj
608 Глава 13
После всех этих изменений наш сайт должен быть доступен в Интернете по временно
му доменному имени (в нашем случае это cc52289-django-n86bo.twl.ru). Для чистоты
эксперимента копируем эту ссылку и вставляем ее в адресную строку интернет
браузера. Если никаких ошибок не было, то должна открыться главная страница наше
го сайта (рис. 13.31 ).
= @)
0 cc52289-djanga-n8бba.t\•, Х + о.
< с gg
D Пане11ь з.аК11адоk (... tlJ Д5иабилеты � Янд.е.кс
О Хотите сдела-тс Opera сбоим nовседм:е�ным бр.ау3е... Кок я •.югу :пс сдел,ат.ь-? х
Вход
Сведения из базы данных
т
Количес во книг - 6 На складе в наличии 9 Количество авторов - 7
Книги
Если ваша страница загрузилась, значит, все настройки в процессе переноса были
выполнены правильно. Но это был тестовый запуск с подключением к БД на SQLite.
Теперь пора переключить наш сайт на СУДБ MySQL.
Приложения Django и MySQL 609
'default':
'ENGINE': 'django.dЬ.ba<;:kends.sqliteЗ',
'NАМЕ': BASE_DIR / '<lli.sqliteЗ',
DATAВASES =
'default':
'ENGINE': 'django.dЬ.backends.mysql', # Actd 'mysql'
'NАМЕ': 'сс52289_n86Ьо',
'USER': 'сс52289_n86Ьо',
'PASSWORD': 'здесь_ваш_пароль',
+
i vh314.timeweb.ru/pma/?&db=cc52289_n86bo
*
�•io®.e} е
*
iш Обзор \'J,t:G-rpyктypa
*
auth_user_groups 11:J Обзор 1J1iСтруктура
*
auth_user_user_permissions Обзор ;'И)Структура
б:J
*
catalog_author iliI] Обзор !J,!,Структура
*
catalog_book � Обзор !И)Структура
о
*
catalog_Ьookiвstвпce iш Обзор :И С1руктура
о
*
catalog_book_author @Обзор ]1!СтруltТ)•ра
о
*
catalog_genre б:J Обзор :И!Структура
+
о
•
catalog_language f[j Обзор [},тJСтруктура
�)t aitalog_Ьooklnstance
о catalog__puЫisher
*
cf.F.'И' aitalog_Ьook_aulhor i:::J Обзор !И)Структура
� aitalog_genre catalog_status
*
[J Обзор J-i!С1руктура
t� catalog_language
*
�)+1' catalog_publisher django_admin_log l!J] Обзор М Струr.тура
;i.}i!j,$ catalog_status i!'i!J Обзор :И'Структура
Рис. 13.32. Таблицы приложения catalog после миграции таблиц базы данных
0 cc52289-dj>n90-n86Ьo,I\, Х + о..
< С 88 & Не защищена cc52289-django-n8бbo.twl.ru
D Пан�ь 3аКАЦО11: (... ■ Аеиа61оt.11е1Ъ1
() Хотите СА,е11ать Opera своиu nosceд,.. Как в могу это сд�1аrь? Дr,, устi!IНОl!lить е качеСТU брау,ера no уuо11ча�нию х
Вход
Сведения из базы данных
Количество книr - О На складе в нат,чии Количество авторов 11
о '
'
Книги
Количество посещений данной страницы - 1
0 Администрирование саюс Х о.
< > С 88 А Не за ищено cc52289-django-n8бbo.twl.ru/admin/
О Хотите сделать Opera своим no&ee-.., Как я моrу эrо· сдеJJать? Вход от име.ни
адми нистратора
Администnиnование Django
Добро n<и.-а.повать, auatoly. � !Измеmm, паропъ f В1!!Ш11
Администрирование сайта
Qiшlog
Allth9n Д� Изм еяить
Book inst;aaces ДQОШШ> Измениrъ
� Д�ъ Измеюпь
� д22Ш!Ш:1> Из,'\lенип.
ШIIDIU Д� Изменить
PuЫishers Д�Из.'1еmm.
� д�Измеюпь
Пользователи и Л1УШП�!
uooшw Добави ть Изменить
Пользователи ДQОМШI> Измеиить
Папки Описание
Глава 2 Листинги 2.1-2.9
Глава 3 Листинги 3.1-3.18
Глава 4 Листинги 4.1-4.3
Глава 5 Листинги 5.1-5.19
Глава 6 Листинги 6.1-6.50
Глава 7 Листинги 7.1-7.65
Глава 8 Листинги 8.1-8.40
Глава 9 Листинги 9.1-9.27
Глава 10 Листинги 10.1-10.30
Глава 11 Листинги 11.1-11.48
Глава 12 Листинги 12.1-12.11
в г
Варианты отображения полей на форме260 Гвидо Ван Россум15
Ввод Гиперссьmки56
◊ IР-адреса238 Главная модель296,300
◊ временного промежутка232 Главная страница сайта500
◊ даты229 Главная таблицаБД296,297,299,383
◊ даты и времени230 Главное меню сайта424
◊ десятичных чисел231
◊ значений времени246
◊ текста226 д
◊ текста с проверкой соответствия заданным ДвижокБД SQLite114,362
форматам252 Декоратор @register404
◊ текста типа «slug» 246 Динамический сайт40,41
◊ текста, соответствующего регулярному Диспетчер URL-aдpecoв (URLs) 106
выражению245 Дистрибутив Python17
◊ универсального указателя ресурса (URL) Добавление данных вБД287
250 Домашняя страница сайта484
◊ универсального уникального Дочерняя таблица383
идентификатора UUID 251 ◊ вБД299
◊ целых чисел240
◊ чисел с плавающей точкой238
◊ электронного адреса233
з
Веб-сайт39,40 Зависимая модель296,300
Веб-сервер Django547 Зависимая таблицаБД296,297
Веб-страница39, 47 Заголовок документа45
620 Предметный указатель
Запрос
О GET 315
л
О get_queryset() 508 Логика проверки ввода 223
О HttpRequest 433
О POST 315 ·
Защита
м
О от межсайтовой подделки запроса 211 Маркер 49
О приложения от CSRF-aтaк 221,276 Маркированные списки 49
Маршрутизация запросов 123,144
и Маршруты 124,129
Менеджер
Идентификаторы полей 219 О SQLiteStudio 35,36,314,391,400
Идентификация пользователя 483 О баз данных SQLite 35
Изображения 180 О пакетов pip 16,28,29
Имя поля 374 О работы с базами данных SQLiteStudio 37
Интегрированная среда разработки 15,18 Метаданные 376,377
Интегрирующий объект QuerySet 378 Метка поля 219,220,374
Интерактивная среда разработки Метод
О IDE PyCharm 21 О as_view() 540
О программного кода PyCharm 37 О admin.site.register() 404
Интернет-браузер 40,47
О Emai!Validator 233
Интерпретатор Python 16,17,20,32,33,37
Использование сессий 472 О filter() 378
О GET 529
к О get_absolute_url() 386
О is_valid() 264
Календарь 396 О objects.all() 378
Каскадное удаление 297,299 О POST 529
Каскадные таблицы стилей (Cascading Style О RegexValidator 245
Sheets, CSS) 39,40,56,172,176 О save() 377
Класс 58,119 О URLValidator 250
О foпns.Foпn 215 О validate_slug 246
О HttpResponse (ответ НТТР) 124 О validate_unicode_slug 246
О HttpResponse() 364 О ValidationEпor 245
О inlines 412 Механизм
О ListView 439 О валидации 262
О LoginRequiredMixin 505 О переадресации 140
О Meta 376,537 Миграция 281,282,298,306,308,360,474
О Mode!Admin 403 О данных 389,407
О reverse 380 Множественный выбор данных из списка
О TemplateResponse 145,155,162 243,249
О TemplateView 183 Модели 107,366,371,394
О формы Foпn() 515,533,539 О авторизации 474
О формы Mode!Form() 533,537-539 О данных 278,297,360,373,385,387,391,
Ключевое поле (id) 375 402,406,422,423,537
Ключевые поля БД 299 Модель 279
Код JavaScript 60,513 О данных Django 280
Конструктор Модуль 119
О models.ForeignKey 297
О models.ManyToManyField 302
О models.OneToOneField() 306
Кортеж list_ display 404
Предметный указатель 621
н п
Настройка Пакетный менеджер pip 18
◊ DEBUG 551 Панель
◊ SECRET_КEY 551 ◊ администратора сайта 393,476,484
◊ шаблонов 145 ◊ администрирования Django 411
Несвязанная форма 515 ◊ администрирования сайта 394,400
Нумерованные списки 50 ◊ календаря 415
Параметр 159
о ◊ DAТABASES 280
◊ ENGINE 280
Облачные решения 548 ◊ label 220
Облачный сервис Heroku 548 ◊ NАМЕ280
Обновление объекта в БД 290 ◊ page_obj 451
Обобщенные классы 512,537 ◊ request 470
◊ редактиро�ания форм 545 ◊ success url 539
◊ базовые классы визуализации данных 438 ◊ widget 255
◊ создания страниц 537 Параметры
◊ отображения списков 448 ◊ корректности вводимых данных 262
Общие аргументы полей моделей 374 ◊ строки запроса 138
Объект 371 ◊ передаваемые через интернет-адрес 137
◊ HttpResponse 124,277 ◊ передаваемые через строку запроса 137
◊ QuerySet 288,289,378 Пароль
◊ request 123,124 ◊ пользователей 492
◊ UploadedFile 234,239 ◊ суперпользователя 505
◊ запроса пользователя 119 Первичный ключ 302,305,386,388,541
◊ формы 216 ◊ в таблице базы данных 283
Объектно-ориентированный язык JavaScript ◊ для модели 375
58 Переадресация 140,142
Объекты 279 ◊ временная 140
◊ Python 107 Передача в шаблон сложных данных 161
◊ модели данных 308 Переменная
Объявление стиля 172 ◊ context 473
Окно ◊ session 470
◊ администрирования сайта 394 ◊ urlpattems (шаблон URL) 125
◊ терминала PyCharm 107 Платформа как Сервис (PaaS) 548
Окружение развертывания 548 Подсказки 260
Основные способы доступа к данным модели Поиск хостинга 547,583
370 Поле
Основные типы полей таблиц 370 ◊ exclude 538
Ответ (response) 123 ◊ fields 538
Отключение атрибута required 263 Пользовательские аккаунты 468
Отношение Поля формы 215,223,538
◊ «многие ко многим» 375 Порядок следования полей на форме 258
◊ «один ко многим» 375,379 Постоянная переадресация 141
Отношения между моделями 371 Постраничный вывод (Pagination) 448
Очистка данных 515 ◊ длинных списков 468
Постраничный показ данных 438
Представление (view) 106,107,182,308,402,
425,427,468,472,505,514,539
622 Предметный указатель
с т
Свойство Таблица базы данных 281,308,356,373
◊ help_text 259 Таблицы-«источники» 302
◊ initial 257 Тег label 513
◊ формы error_css_class 272 Теги 39,45,47,48,50,51, 59
◊ формы required_css_class 272 Текст «slug» 246
Связанная таблица 383 Тело документа 45
Связанная форма 515 Терминал PyChann 281,283,297,299,302,
Связанные данные 299 306,359,360,389,392,491,504
Связующая таблица 303,384 Тестирование приложения 361
Связь Тип запроса
◊ «многие ко МНОГИМ» 301-303,305,384,397 ◊ GET277
◊ «один к одному» 305,306 ◊ POST277
◊ «один ко многим» 296,305,382,383,387, Типовые модульные сетки 53
397,405,503 Типы отношений в БД 296
Предметный указатель 623
Типы полей
◊ в модели данных Django284
х
◊ в различных СУБД 286,287 Хешированиый пароль 104
◊ в формах Django222 Хеш-функция 104
Хостинг-провайдер 548, 549
у
Удаление
ч
◊ данных из БД 291 Чтение данных из БД 288
◊ объектов модели321
Универсальный указатель ресурса (URL) 250
Универсальный уникальный идентификатор
ш
UUID 251 Шаблон
Учетная запись superuser (суперпользователь) ◊ НТМL-страницы539
392 ◊ регулярного выражения 236
◊ страницы31 О
ф Шаблоны107,145
◊ URL-aдpecoв540
Файл миграции282,389,504 ◊ преобразования URL-aдpecoв 468
Файлы cookie104,470,471
Форма211,483,524,531
◊ НТМL512 3
Формы209,220,278,358,391 Электронный адрес 233
◊ аутентификации 474 Элемент input типа type="submit" 513
Фреймворк SQLite Studio16
Функции-представления130
Функция119 я
◊ «обратного просмотра» (reverse lookup) 446
Язык
◊ path128
◊ НТМL40,45,512,513
◊ path() 127,134,135,137
◊ Perl41, 42
◊ re_path135
◊ Python15-17,19,21,29,35,37, 42,43,103
◊ re_path() 127,128
◊ SQL279,287
◊ render (предоставлять) 150
◊ render() 145,155,433,439 ◊ сценариев общего назначения РНР 41,42
◊ reverse_lazy() 539
◊ url() 439,443,453,456
BHV.RU
ИНТЕРНЕТ-МАГАЗИН Интернет-магазин издательства «БХВ•
• Более 25 лет на российском рынке
• Книги и наборы по электронике
и робототехнике по издательс
КНИГИ, РОБОТЫ,
ЭЛЕКТРОНИКА