Открыть Электронные книги
Категории
Открыть Аудиокниги
Категории
Открыть Журналы
Категории
Открыть Документы
Категории
Django 3.0.
Практика
создания
юб-сайтов
Vв
на Python
Санкт-Петербург
«БХВ-Петербург»
2021
УДК 004.738.5+004.43 8Python
ББК 32.973.26-018.1
Д75
Дронов В. А.
Д75 Django 3.0. Практика создания веб-сайтов на Python. — СПб.:
БХВ-Петербург, 2021. — 704 с.: ил. — (Профессиональное программирование)
ISBN 978-5-9775-6691-9
Книга посвящена созданию веб-сайтов на языке Python с использованием веб
фреймворка Django 3.0. Рассмотрены новинки Django 3.0 и дано наиболее полное
описание его инструментов: моделей, контроллеров, шаблонов, средств обработки
пользовательского ввода, включая выгруженные файлы, разграничения доступа,
посредников, сигналов, инструментов для отправки электронной почты, кэширо
вания и пр. Рассмотрены дополнительные библиотеки, производящие обработку
BBCode-тегов, CAPTCHA, вывод графических миниатюр, аутентификацию через
социальные сети (в частности, ’’ВКонтакте"), интеграцию с Bootstrap. Рассказано
о программировании веб-служб REST, использовании и настройке административ
ного веб-сайта Django, публикации сайтов с помощью веб-сервера Uvicom, работе
с базами данных PostgreSQL, кэшировании сайтов с помощью Memcached и Redi.
Подробно описано создание полнофункционального веб-сайта — электронной доски
объявлений, веб-службы, работающей в его составе, и тестового фронтенда для
нее, написанного на Angular.
Электронное приложение-архив на сайте издательства содержит коды всех при
меров.
Для веб-программистов
УДК 004.738.5+004.438Python
ББК 32.973.26-018.1
Введение................................................................................................................................................17
Что такое веб-фреймворк?......................................................................................................................... 17
Почему Django?............................................................................................................................................ 18
Что нового в Django 3.0 и новой книге?................................................................................................ 19
Использованные программные продукты............................................................................................. 19
Типографские соглашения........................................................................................................................ 20
Заключение....................................................................................................................................... 684
Почему Django?
□ Django — это современные стандарты веб-разработки: схема ’’модель-представ-
ление-контроллер”, использование миграций для внесения изменений в базу
данных и принцип ’’написанное однажды применяется везде” (или, другими сло
вами, ”не повторяйся”).
□ Django — это полнофункциональный фреймворк. Для написания типичного сай
та достаточно его одного. Никаких дополнительных библиотек, необходимых,
чтобы наше веб-творение хотя бы заработало, ставить не придется.
□ Django — это высокоуровневый фреймворк. Типовые задачи, наподобие соеди
нения с базой данных, обработки данных, полученных от пользователя, сохра
нения выгруженных пользователем файлов, он выполняет самостоятельно.
А еще он предоставляет полнофункциональную подсистему разграничения дос
тупа и исключительно мощный и удобно настраиваемый административный
веб-сайт, которые, в случае применения любого другого фреймворка, нам при
шлось бы писать самостоятельно.
□ Django — это удобство разработки. Легкий и быстрый отладочный веб-сервер,
развитый механизм миграций, уже упомянутый административный веб-сайт —
все это существенно упрощает программирование.
□ Django — это дополнительные библиотеки. Нужен вывод графических миниа
тюр? Требуется обеспечить аутентификацию посредством социальных сетей?
Необходима поддержка CAPTCHA? На диске копятся ’’мусорные” файлы?
Ставьте соответствующую библиотеку — и дело в шляпе!
□ Django — это Python. Исключительно мощный и, вероятно, самый лаконичный
язык из всех, что применяются в промышленном программировании.
Эта книга посвящена Django. Она описывает его наиболее важные и часто при
меняемые на практике функциональные возможности, ряд низкоуровневых инст
рументов, которые также могут пригодиться во многих случаях, и некоторые
дополнительные библиотеки. А в конце, в качестве практического упражнения,
рассказывает о разработке полнофункционального сайта электронной доски объяв
лений.
Внимание!
Автор предполагает, что читатели этой книги знакомы с языками HTML, CSS, JavaScript,
Python, принципами работы СУБД и имеют базовые навыки в веб-разработке. В книге
все это описываться не будет.
Электронное приложение
Содержит программный код сайта электронной доски объявлений и доступно на FTP-
сервере издательства "БХВ-Петербург" по ссылке ftp://ftp.bhv.ru/9785977566919.zip
и на странице книги на сайте www.bhv.ru (см. приложение).
Введение 19
Типографские соглашения
В книге будут часто приводиться форматы написания различных языковых конст
рукций, применяемых в Python и Django. В них использованы особые типографские
соглашения, перечисленные далее.
□ В угловые скобки (о) заключаются наименования различных значений, которые
дополнительно выделяются курсивом. В реальный код, разумеется, должны
быть подставлены конкретные значения. Например:
django-admin startproject <имя проекта>
Здесь вместо подстроки имя проекта должно быть подставлено реальное имя
проекта.
□ В квадратные скобки ([]) заключаются необязательные фрагменты кода. На
пример:
django-admin startproject <имя проекта> [<путь к папке проекта>]
'bboard.apps.BboardConfig',
]
Вводный курс
На заметку
Эта книга не содержит описания Python. Документацию по этому языку программиро
вания можно найти на его "домашнем" сайте https://www.python.org/.
Внимание!
Если исполняющая среда Python установлена в папке Program Files или Program Files (х86),
то для установки любых дополнительных библиотек командную строку следует запус
тить с повышенными правами. Для этого надо найти в меню Пуск пункт Командная
строка (в зависимости от версии Windows он может находиться в группе Стандарт
ные или Служебные), щелкнуть на нем правой кнопкой мыши и выбрать в по
явившемся контекстном меню пункт Запуск от имени администратора (в Windows 10
этот пункт находится в подменю Дополнительно).
1.4. Приложения
Приложение в терминологии Django — это отдельный фрагмент функционально
сти разрабатываемого сайта, более или менее независимый от других таких же
фрагментов и входящий в состав проекта. Приложение может реализовывать рабо
ту всего сайта, его раздела или же какой-либо внутренней подсистемы сайта,
используемой другими приложениями.
Любое приложение представляется обычным пакетом Python (пакет приложения),
в котором содержатся модули с программным кодом. Этот пакет находится в папке
проекта — там же, где располагается пакет конфигурации. Имя пакета приложения
станет именем самого приложения.
Нам нужно сделать так, чтобы наш сайт выводил перечень объявлений, оставлен
ных посетителями. Для этого мы создадим новое приложение, которое незатейливо
назовем bboard.
Гпава 1. Основные понятия Django. Вывод данных_________________________________ 29
Внимание!
Подсистема тестирования кода, реализованная в Django, в этой книге не рассматри
вается, поскольку автор не считает ее сколь-нибудь полезной.
’bboard.apps.BboardConfig’,
]
1.5. Контроллеры
Контроллер Django— это код, запускаемый при обращении по интернет-адресу
определенного формата и в ответ выводящий на экран определенную веб-страницу.
Внимание!
В документации по Django используется термин "view" (вид, или представление).
Автор книги считает его неудачным и предпочитает применять термин "контроллер",
тем более что это устоявшееся название программных модулей такого типа.
def index(request):
return HttpResponse(’’Здесь будет выведен список объявлений.")
Глава 1. Основные понятия Django. Вывод данных__________________________________ 31_
Наш контроллер — это, собственно, функция index (). Единственное, что она дела
ет, — отправляет клиенту текстовое сообщение: Здесь будет выведен список
объявлений. Но это только пока...
Любой контроллер-функция в качестве единственного обязательного параметра
принимает экземпляр класса HttpRequest, хранящий различные сведения о полу
ченном запросе: запрашиваемый интернет-адрес, данные, полученные от посетите
ля, служебную информацию от самого веб-обозревателя и пр. По традиции этот
параметр называется request. В нашем случае мы его никак не используем.
В теле функции мы создаем экземпляр класса HttpResponse (он объявлен в модуле
django.http), который будет представлять ответ, отправляемый клиенту. Содержи
мое этого ответа — собственно текстовое сообщение — указываем единственным
параметром конструктора этого класса. Готовый экземпляр класса возвращаем
в качестве результата.
Что ж, теперь мы с гордостью можем считать себя программистами — поскольку
уже самостоятельно написали какой-никакой программный код. Осталось запус
тить отладочный веб-сервер, набрать в любимом веб-обозревателе адрес вида
http://localhost:8000/bboard/ и посмотреть, что получится...
Минуточку! А с чего мы взяли, что при наборе такого интернет-адреса Django за
пустит на выполнение именно написанный нами контроллер-функцию indexO?
Ведь мы нигде явно не связали интернет-адрес с контроллером. Но как это сде
лать?..
urlpatterns = [
path (’admin/’, admin.site.urIs),
]
urlpatterns = [
path(’bboard/’, index),
path(’admin/’, admin.site.urIs),
]
Рис. 1.2. Результат работы нашего первого контроллера — простое текстовое сообщение
urlpatterns = [
path('’, index),
]
Наконец, исправим код модуля urls.py из пакета конфигурации, как показано в лис
тинге 1.5.
34 Часть I. Вводный курс
urlpatterns = [
path(’bboard/’, include(’bboard.urls’)),
path(’admin/', admin.site.urls),
]
1.7. Модели
Настала пора сделать так, чтобы вместо намозолившего глаза текстового сообще
ния выводились реальные объявления, хранящиеся в таблице базы данных. Для
этого нам понадобится прежде всего объявить модель.
Модель — это класс, описывающий определенную таблицу в базе данных, в част
ности набор имеющихся в ней полей. Отдельный экземпляр класса модели пред
ставляет отдельную запись таблицы, позволяет получать значения, хранящиеся
в полях записи, и заносить в них новые значения. Модель никак не привязана
к конкретному формату базы данных.
Модели объявляются в модуле models.ру пакета приложения. Изначально этот
модуль пуст.
Гпава 1. Основные понятия Django. Вывод данных_________________________________ 35
class Bb(models.Model):
title = models.CharField(max_length=50)
content = models.TextField(null=True, blank=True)
price = models.FloatField(null=True, blank=True)
published = models.DateTimeField(auto_now_add=True, db_index=True)
сама СУБД будет заносить в него уникальные номера. В моделях Django такое поле
явно объявлять не надо — фреймворк создаст его самостоятельно.
Сохраним исправленный файл. Сейчас мы сгенерируем на его основе миграцию,
которая создаст в базе данных все необходимые структуры.
На заметку
По умолчанию вновь созданный проект Django настроен на использование базы дан
ных в формате SQLite, хранящейся в файле db.sqlite3 в папке проекта. Эта база дан
ных создается при первом обращении к ней.
1.8. Миграции
Миграция— это программа, сгенерированная на основе заданной модели и соз
дающая в базе данных все описанные этой моделью структуры: таблицу, поля,
индексы, правила и связи.
Чтобы сгенерировать миграцию на основе модели вь, переключимся в командную
строку, проверим, остановлен ли отладочный веб-сервер и находимся ли мы в пап
ке проекта, и дадим команду:
manage.py makemigrations bboard
class Migration(migrations.Migration) :
initial = True
dependencies = [ ]
operations = [
migrations.CreateModel(
name='Bb’,
fields=[
(’id’, models.AutoField(auto_created=True,
primary_key=True, serialize=False,
verbose name=’ID’)),
Глава 1. Основные понятия Django. Вывод данных__________________________________ 37_
(’title’, models.CharField(max_length=50)),
(’content', models.TextField(blank=True, null=True)),
('price', models.FloatField(blank=True, null=True)),
('published', models.DateTimeField(auto_now_add=True,
db_index=True)),
],
) ,
]
Код миграции вполне понятен и напоминает код написанной ранее модели. Созда
ваемая в базе данных таблица будет содержать поля id, title, content, price
и published. Ключевое поле id для хранения уникальных номеров записей Django
создаст самостоятельно.
На заметку
Инструменты Django для программирования моделей описаны на страницах
https://docs.djangoproject.eom/en/3.0/topics/migrations/ и
https://docs.djangoproject.eom/en/3.0/howto/writing-migrations/ .
— Create model Bb
Этот код был сгенерирован для СУБД SQLite (вспомним— проект Django по
умолчанию использует базу данных этого формата). Если применяется другая
СУБД, результирующий SQL-код будет соответственно отличаться.
Налюбовавшись на нашу первую миграцию, выполним ее. Для этого наберем
в командной строке команду:
manage.py migrate
38 Часть I. Вводный курс
Внимание!
Многие стандартные приложения, поставляющиеся в составе Django, хранят свои
данные в базе и для создания всех необходимых таблиц и индексов включают в себя
набор миграций. Команда migrate выполняет все миграции, входящие в состав всех
приложений проекта и не выполнявшиеся ранее.
Судя по выводящимся в командной строке сообщениям, таких миграций много —
десятка два. Дождемся, когда их выполнение завершится, и продолжим.
Отлично! Сохранилось.
Атрибут класса рк, поддерживаемый всеми моделями, хранит значение ключевого
поля текущей записи. А это значение может быть получено только после сохране
ния записи в базе.
Глава 1. Основные понятия Django. Вывод данных__________________________________ 39
Да, можно поступить и так: создать ’’пустую” запись модели, записав вызов конст
руктора ее класса без параметров и занеся нужные значения в поля позже.
Что-то во втором объявлении маловато информации о продаваемой машине...
Давайте дополним ее:
»> Ь2.content = "’Жигули", 1980 года, ржавая, некрашеная, сильно битая'
»> Ь2. save ()
»> Ь2.content
'"Жигули", 1980 года, ржавая, некрашеная, сильно битая'
1 : Дача
2 : Автомобиль
3 : Дом
2 : Автомобиль
1 : Дача
3 : Дом
Метод order by () диспетчера записей сортирует записи по значению поля, имя ко
торого указано в параметре, и сразу же возвращает набор записей, получившийся
в результате сортировки.
Извлечем объявления о продаже домов:
»> for b in Bb.objects.filter(title=’Дом'):
... print(b.pk, ’: ', b.title)
3 : Дом
Метод delete () модели, как уже понятно, удаляет текущую запись и возвращает
сведения о количестве удаленных записей, обычно малополезные.
Глава 1, Основные понятия Django. Вывод данных__________________________________ 41
Ладно, хватит пока! Выйдем из консоли Django, набрав команду exit ().
def index(request):
s = ’Список объявлений\г\п\г\п\г\п'
for bb in Bb.objects.order_by('-published’):
s += bb.title + ’\r\n’ bb.content + ’\r\n\r\n’
return HttpResponse(s, content_type=’text/plain; charset=utf-8 ’)
1.11. Шаблоны
Шаблон— это образец для генерирования веб-страницы, отправляемой клиенту
в составе ответа. Генерированием страниц на основе шаблонов занимается подсис
тема Django, называемая шаблонизатором.
Шаблон Django — это файл с HTML-кодом страницы, содержащий особые коман
ды шаблонизатора: директивы, теги и фильтры. Директивы указывают поместить
в заданное место HTML-кода какое-либо значение, теги управляют генерировани
ем содержимого, а фильтры выполняют какие-либо преобразования указанного
значения перед выводом.
По умолчанию шаблонизатор ищет все шаблоны в папках templates, вложенных
в папки пакетов приложений (это поведение можно изменить, задав соответствую
щие настройки, о которых мы поговорим в главе 77). Сами файлы шаблонов веб
страниц должны иметь расширение html.
Остановим отладочный сервер. Создадим в папке пакета приложения bboard папку
templates, а в ней — вложенную папку bboard. Сохраним в этой папке наш первый
шаблон index.html, код которого приведен в листинге 1.9.
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>PnaBHa4 :: Доска объявлений</1^1е>
</head>
<body>
<Ь1>0бъявления</Ь1>
{% for bb in bbs %}
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p>{{ bb.published|date:"d.m.Y H:i:s" }}</p>
</div>
{% endfor %}
</body>
</html>
{% endfor %}
def index(request) :
template = loader.get_template('bboard/index.html')
bbs = Bb.objects.order_by(’-published’)
context = {’bbs’: bbs}
return HttpResponse(template.render(context, request))
def index(request):
bbs = Bb.objects.order_by (’-published’)
return render(request, ’bboard/index.html', {’bbs’: bbs})
Для создания суперпользователя с таким паролем следует ввести символ "у" и на
жать <Enter>.
Как только суперпользователь будет успешно создан, появится уведомление:
Superuser created successfully.
После этого русифицируем проект Django. Откроем модуль settings.py пакета кон
фигурации и найдем в нем вот такое выражение:
LANGUAGE_CODE = *en-us'
Переменная language code задает код языка, используемого при выводе системных
сообщений и страниц административного сайта. Изначально это американский анг
лийский язык (код en-us). Исправим это выражение, занеся в него код русского
языка:
LANGUAGE_CODE = 'ru'
admin.site.register(Bb)
Здесь мы можем:
□ щелкнуть на гиперссылке Добавить <имя класса модели>, чтобы вывести
страницу добавления новой записи (рис. 1.9). Занеся в элементы управления
нужные данные, нажмем кнопку:
• Сохранить — для сохранения записи и возврата на страницу списка записей;
• Сохранить и продолжить редактирование — для сохранения записи с воз
можностью продолжить ее редактирование;
• Сохранить и добавить другой объект — для сохранения записи и подготов
ки формы для ввода новой записи;
□ щелкнуть на нужной записи, чтобы вывести страницу ее правки. Эта страница
похожа на страницу для добавления записи (см. рис. 1.9), за исключением того,
что в наборе имеющихся на ней кнопок будет присутствовать еще одна — Уда
лить, выполняющая удаление текущей записи;
Глава 1. Основные понятия Django. Вывод данных 49
Одним словом, нам надо задать параметры как для полей модели, так и для самой
модели.
Откроем модуль models.py пакета приложения bboard и исправим код класса моде
ли вь, как показано в листинге 1.13.
class Meta:
verbose_name_plural = 'Объявления'
verbose_name = 'Объявление'
ordering = ['-published']
def index(request):
bbs = Bb.objects.all()
class BbAdmin(admin.ModelAdmin) :
list_display = (’title’, ’content’, ’price’, ’published’)
list_display_links = (’title’, ’content’)
search_fields = (’title’, ’content’, )
Рис. 1.10. Список записей модели ВЬ после указания для нее редактора
(была выполнена фильтрация по слову "газ")
class Meta:
verbose_name_plural = ’Рубрики’
verbose_name = 'Рубрика’
ordering = [’name’]
Модель содержит всего одно поле name, которое будет хранить название рубрики.
Для него мы сразу велели создать индекс, т. к. будем выводить перечень рубрик
отсортированным по их названиям.
Теперь нужно добавить в модель вь поле внешнего ключа, устанавливающее связь
между текущей записью этой модели и записью модели Rubric, т. е. между объяв-
54 Часть I. Вводный курс
лением и рубрикой, к которой оно относится. Таким образом будет создана связь
’Ъдин-со-многими", при которой одна запись модели Rubric (рубрика) будет связана
с произвольным количеством записей модели вь (объявлений). Модель Rubric ста
нет первичной, а вь — вторичной.
Создадим во вторичной модели такое поле, назвав его rubric1:
class Bb(models.Model):
class Meta:
На заметку
Помимо всего прочего, эта миграция задаст для полей модели вь параметры
verbose_name, а ДЛЯ самой МОДвЛИ — параметры verbose_namejplural, verbose_name И
ordering, которые мы указали в главе 1. Скорее всего, это делается, как говорится,
для галочки — подобные изменения, произведенные в классе модели, в действитель
ности никак не отражаются на базе данных.
class Meta:
Рис. 2.2. Для указания значения поля внешнего ключа применяется раскрывающийся список
ния выбранной. Так что мы сразу же сможем при необходимости добавить новую
рубрику, исправить или удалить существующую.
Осталось сделать так, чтобы в списке записей модели вь, помимо всего прочего,
выводились рубрики объявлений. Для чего достаточно добавить в последователь
ность имен полей, присвоенную атрибуту list display класса BbAdmin, поле rubric:
class BbAdmin (admin. Model Admin) :
list_display = (’title’, ’content’, ’price’, ’published’, 'rubric')
Обновим страницу списка объявления — и сразу увидим в нем новый столбец Руб
рика. Отметим, что и здесь в качестве значения поля выводится строковое пред
ставление связанной записи модели.
2.3. URL-параметры
и параметризованные запросы
Логичным шагом выглядит разбиение объявлений по рубрикам не только при
хранении, но и при выводе на экран. Давайте создадим на пока что единственной
странице нашего сайта панель навигации, в которой выведем список рубрик, и при
щелчке на какой-либо рубрике будем выводить лишь относящиеся к ней объявле
ния. Остановим отладочный сервер и подумаем.
Чтобы контроллер, выводящий объявления, смог выбрать из модели лишь относя
щиеся к указанной рубрике, он должен получить ключ рубрики. Его можно пере
дать через GET-параметр: /bboard/?rubric=<jcij04 рубрики>.
Гпава 2. Связи. Ввод данных. Статические файлы_________________________________ 57
urlpatterns = [
path (• <int: rubric_id>/' , by_rubric) ,
path(’’, index),
1
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8”>
<title>{{ current_rubric. name }} :: Доска объявлений<А^1е>
</head>
<body>
<hl>Объявления</hl>
<Ь2>Рубрика: {{ current_rubric.name }}</h2>
<div>
<a href="/bboard/”>Главная</а>
{% for rubric in rubrics %}
<a href="/bboard/{{ rubric.pk }}/”>{{ rubric.name }}</a>
{% endfor %}
</div>
{% for bb in bbs %}
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p>{{ bb.published|date:"d.m.Y H:i:s” }}</p>
</div>
{% endfor %}
</body>
</html>
def index(request) :
bbs = Bb.objects.all()
Глава 2. Связи. Ввод данных. Статические файлы_________________________________ 59_
rubrics = Rubric.objects.all()
context = {’bbs’: bbs, ’rubrics’: rubrics}
return render(request, ’bboard/index.html’, context)
<!DOCTYPE html>
<html>
<head>
<meta charset=’’UTF-8”>
<title>r\naBHa4 : : Доска объявлений<^^1е>
</head>
<body>
<111>0бъявления</!11>
<div>
<a href=”/bboard/">Главная</а>
{% for rubric in rubrics %}
<a href="/bboard/{{ rubric.pk }}/">{{ rubric.name }}</a>
{% endfor %}
</div>
{% for bb in bbs %}
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p><a href="/bboard/{{ bb.rubric.pk }}/’’>
{{ bb.rubric.name }}</aX/p>
<p>{{ bb.published|date:"d.m.Y H:i:s" }}</p>
</div>
{% endfor %}
</body>
</html>
urlpatterns = [
path(’<int:rubric_id>/', by_rubric, name-1by_rubric'),
path (’ ’, index t name=' index') f
]
2.6. Контроллеры-классы
Обрабатывать формы, связанные с моделью, можно в контроллерах-функциях. Но
лучше использовать высокоуровневый контроллер-класс, который сам выполнит
большую часть действий по выводу и обработке формы.
Наш первый контроллер-класс будет НОСИТЬ ИМЯ BbCreateView. Его мы объявим
в модуле views.py пакета приложения. Код этого класса показан в листинге 2.7.
class BbCreateView(CreateView):
template_name = 'bboard/create.html’
form_class = BbForm
success_url = ’/bboard/’
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<Ъ1Ъ1е>Добавление объявления : : Доска объявлений<^^1е>
</head>
<body>
<Ь1>Добавление объявления</Н1>
<div>
<а href="{% url ’index’ %}">Главная</а>
{% for rubric in rubrics %}
<a href="{% url ’by_rubric’ rubric.pk %}”>
{{ rubric.name }}</a>
{% endfor %}
</div>
<form method=”post”>
{% csrf_token %}
{{ form.as_p }}
<input type="submit” value=”Добавить">
</form>
</body>
</html>
class BbCreateView(CreateView):
successuri = reverse_lazy('index')
Гпава 2. Связи. Ввод данных. Статические файлы 65
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>{% block title %}Главная{% endblock %} ::
Доска объявлений*^title>
</head>
<body>
<header>
<hl>Объявления</hl>
</header>
<nav>
<a href=’’{% url ’index’ %}”>Главная</а>
<a href=”{% url ’add’ %}”>Добавить</а>
{% for rubric in rubrics %}
<a href=’’{% url ’by_rubric’ rubric.pk %}">
{{ rubric.name }}</a>
{% endfor %}
</nav>
<section>
{% block content %}
{% endblock %}
</section>
</body>
</html>
Оно будет выведено на страницу, если производный шаблон не задаст для блока
свое содержимое.
Сделаем шаблон bboard\index.html производным от шаблона layout\basic.html. Новый
код этого шаблона приведен в листинге 2.10.
{% extends "layout/basic.html” %}
{% block content %}
{% for bb in bbs %}
Гпава 2. Связи. Ввод данных. Статические файлы_________________________________ 67
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p><a href="(% url ’by_rubric’ bb.rubric.pk %}">
{{ bb.rubric.name }}</a></p>
<p>{{ bb.published!date:"d.m.Y H:i:s" }}</p>
</div>
{% endfor %}
{% endblock %}
{% extends "layout/basic.html" %}
{% block content %}
<И2>Рубрика: {{ current_rubric.name }}</h2>
{% for bb in bbs %}
<div>
<h2>{{ bb.title }}</h2>
<p>{{ bb.content }}</p>
<p>{{ bb.published|date:"d.m.Y H:i:s" }}</p>
</div>
{% endfor
{% endblock %}
{% extends "layout/basic.html" %}
{% block content %}
<h2Добавление объявления</112>
<form method="post">
{% csrf_token %}
68 Часть I. Вводный курс
{{ form.as_p }}
<input type="submit" value="flo6aBHTb">
</form>
{% endblock %}
header hl {
font-size: 4 Opt;
text-transform: uppercase;
text-align: center;
background: url("bg.jpg") left / auto 100% no-repeat;
}
nav {
font-size: 16pt;
width: 15Opx;
float: left;
}
nav a {
display: block;
margin: lOpx Opx;
}
section {
margin-left: 17Opx;
}
Но где нам сохранить эту таблицу стилей и файл с фоновым изображением bg.jpg?
И вообще, как привязать таблицу стилей к базовому шаблону?
Файлы, содержимое которых не обрабатывается программно, а пересылается кли
енту как есть, в терминологии Django носят название статических. К таким фай
лам относятся, например, таблицы стилей и графические изображения, помещае
мые на страницы.
Остановим отладочный веб-сервер. Создадим в папке пакета приложения bboard
папку static, а в ней— вложенную папку bboard. В последней сохраним файлы
style.css и bg.jpg (можно использовать любое подходящее изображение, загруженное
из Интернета).
Откроем базовый шаблон layout\basic.html и вставим в него следующий код:
{% load static %}
<!DOCTYPE html>
Гпава 2. Связи. Ввод данных. Статические файлы 69
<html>
<head>
</html>
Рис. 2.6. Главная страница сайта после применения к ней таблицы стилей
ЧАСТЬ II
Прежде чем начать писать код сайта, следует создать проект этого сайта, указать
его настройки и сформировать все необходимые приложения.
Если путь к папке проекта не указан, папка проекта будет создана в текущей папке
и получит то же имя, что и сам проект. В противном случае папкой проекта станет
папка с указанным в команде путем.
Папку проекта можно впоследствии переместить в любое другое место файловой
системы, а также переименовать. Никакого влияния на работу проекта эти действия
не оказывают.
На заметку
Настройка file charset, указывающая кодировку текстовых файлов, в частности
файлов шаблонов, с версии 2.2 объявлена устаревшей и не рекомендованной к при
менению. Все текстовые файлы, используемые Django, теперь должны быть сохране
ны в кодировке UTF-8.
На заметку
В абсолютном большинстве случаев веб-сайты хранят данные в одной базе, поэтому
в книге будет описана работа только с одной базой данных. Конфигурирование Django
для использования нескольких баз данных описано на странице https://docs.
djangoproject.eom/en/3.0/topics/db/multi-db/
На заметку
Если приложение содержит только контроллеры, то его можно и не указывать в пара
метре installed apps. Однако делать так все же не рекомендуется.
78 Часть II. Базовые инструменты Django
Значение этого параметра по умолчанию — пустой список. Однако сразу при соз
дании проекта ему присваивается следующий список:
INSTALLED_APPS = [
’django.contrib.admin’,
’dj ango.contrib.auth’,
’dj ango.contrib.contenttypes’r
’dj ango.contrib.sessions’,
’django.contrib.messages’t
’dj ango.contrib.staticfiles’,
]
MIDDLEWARE = [
’django.middleware.security.SecurityMiddleware’,
’dj ango.contrib.sessions.middleware.SessionMiddleware’r
' dj ango. middleware. common. CommonMiddleware',
’django.middleware.csrf.CsrfViewMiddleware’,
’ dj ango.contrib.auth.middleware.AuthenticationMiddleware’,
'django.contrib.messages.middleware.MessageMiddleware ',
’dj ango.middleware.clickj acking.XFrameOptionsMiddleware ',
]
В нем перечислены стандартные посредники:
□ django.middleware.security.SecurityMiddleware — реализует дополнительную
защиту сайта от сетевых атак;
□ django.contrib.sessions.middleware.SessionMiddleware — обрабатывает Сервер
ные сессии на низком уровне. Используется подсистемами разграничения дос
тупа, сессий и всплывающих сообщений (приложениями django.contrib.auth,
django. contrib. sessions И django. cont rib. messages);
□ django.middleware.common.CommonMiddleware — участвует в предварительной об
работке запросов;
□ django.middleware.csrf.CsrfViewMiddleware — осуществляет защиту ОТ межсай-
товых атак при обработке данных, переданных сайту HTTP-методом POST;
□ django.contrib.auth.middleware.AuthenticationMiddleware — добавляет В объект
запроса атрибут, хранящий текущего пользователя. Через этот атрибут в кон
троллерах и шаблонах можно выяснить, какой пользователь выполнил вход на
сайт и выполнил ли вообще. Используется административным сайтом и подсис
темой разграничения доступа (приложениями django.contrib.admin И django.
contrib. auth);
□ django. contrib.messages .middleware.MessageMiddleware — обрабатывает ВСПЛЫВа-
ющие сообщения на низком уровне. Используется административным сайтом
И ПОДСИСТеМОЙ ВСПЛЫВаЮЩИХ Сообщений (приложениями django. contrib.admin и
dj ango.contrib.messages);
□ django. middleware, click jacking. XFrameOptionsMiddleware— реализует дополни
тельную защиту сайта от сетевых атак.
Если какой-либо из этих посредников не нужен, его можно удалить из списка. Ис
ключение составляют посредники
dj ango.middleware.security .SecurityMiddleware,
d j ango .middleware. common. CommonMiddleware,
d j ango.middleware.clickj acking.XFrameOptionsMiddleware,
dj ango.middleware.csrf.CsrfViewMiddleware
— их удалять не стоит.
80 Часть II. Базовые инструменты Django