Мэтиз. Изучаем Python. Crash course2 n d e d i t i o na h a n d s o n, p r o j e c t b a s e d i n t r o d u c t i o n t o p r o g r a m m i n g
Скачать 6.2 Mb.
|
414 Глава 18 • Знакомство с Django Пространство имен определяется значением, присвоенным app_name в файле learning_logs/urls .py В этой простой странице HTML ссылка заключается в якорный тег: url_ссылки">текст ссылки Генерирование URL-адреса шаблонным тегом существенно упрощает актуали- зацию ссылок. Чтобы изменить URL-адрес в проекте, достаточно изменить схе- му URL в urls .py , а Django автоматически вставит обновленный URL-адрес при следующем запросе страницы. Каждая страница в проекте будет наследовать от base .html , так что в дальнейшем на каждой странице будет содержаться ссылка на домашнюю страницу. В точке вставляется пара тегов block . Блок с именем content резервирует место; информация, попадающая в блок content , будет определяться дочерним шаблоном. Дочерний шаблон не обязан определять каждый блок в своем родителе, так что в родительских шаблонах можно зарезервировать место для любого количества блоков, а дочерний шаблон будет использовать столько из них, сколько потребу- ется. ПРИМЕЧАНИЕ В коде Python почти всегда используются отступы в четыре пробела . Файлы шаблонов обычно имеют больший уровень вложенности, чем файлы Python, по- этому каждый уровень отступа обычно обозначается двумя пробелами . Будьте внима- тельны и действуйте последовательно . Дочерний шаблон Теперь нужно переписать файл index .html так, чтобы он наследовал от base .html Обновленный файл index .html выглядит так: index.html ❶ {% extends "learning_logs/base.html" %} ❷ {% block content %} Learning Log helps you keep track of your learning, for any topic you're learning about. ❸ {% endblock content %} Сравнивая этот файл с исходной версией index .html , мы видим, что заголовок Learning Log заменен кодом наследования от родительского шаблона . В первой строке дочернего шаблона должен находиться тег {% extends %} , который сообщает Django, от какого родительского шаблона он наследует. Файл base .html является частью learning_logs , поэтому learning_logs включается в путь к родительскому шаблону. Эта строка извлекает все содержимое из шаблона base .html и позволяет index .html определить, что должно попасть в пространство, зарезервированное блоком content Построение других страниц 415 Блок content определяется в точке вставкой тега {% block %} с именем content . Все, что не наследуется от родительского шаблона, попадает в блок content . В данном случае это абзац с описанием проекта Learning Log. В точке мы сообщаем о том, что определение content завершено, при помощи тега {% endblock content %} . Наличие имени у {% endblock %} не обязательно, но если шаблон увеличится и станет вклю- чать несколько блоков, будет полезно сразу видеть, какой именно блок завершается. Вероятно, вы уже начинаете понимать преимущества наследования шаблонов: в дочерний шаблон достаточно включить информацию, уникальную для этой страницы. Такой подход не только упрощает каждый шаблон, но и значительно упрощает изменение сайта. Чтобы изменить элемент, общий для многих страниц, достаточно изменить элемент в родительском шаблоне. Внесенные изменения бу- дут автоматически перенесены на каждую страницу, наследующую от этого шабло- на. В проекте из десятков и сотен страниц такая структура значительно упрощает и ускоряет доработку сайта. ПРИМЕЧАНИЕ В больших проектах часто создается один родительский шаблон base . html для всего сайта и родительские шаблоны для каждого крупного раздела сайта . Все шаблоны разделов наследуют от base .html, и каждая страница сайта наследует от ша- блона раздела . При такой структуре вы сможете легко изменять оформление и поведе- ние сайта в целом, любого его раздела или отдельной страницы . Данная конфигурация сильно повышает эффективность работы и стимулирует разработчика к дальнейшему совершенствованию сайта . Страница со списком тем Разобравшись с тем, как эффективно организовать построение страниц, мы можем сосредоточиться на следующих двух страницах: списке всех тем и списке записей по одной теме. На странице тем выводится перечень всех тем, созданных пользо- вателями, и это первая страница, на которой нам придется работать с данными. Схема URL для тем Сначала нужно определить URL для страницы тем. Обычно в таких случаях выбирается простой фрагмент URL, который отражает суть информации, пред- ставленной на странице. Мы воспользуемся словом topics, так что для получения страницы будет использоваться URL http://localhost:8000/topics/ . А вот какие изме- нения следует внести в learning_logs/urls .py : urls.py """Определяет схемы URL для learning_logs.""" urlpatterns = [ # Домашняя страница path('', views.index, name='index'), # Страница со списком всех тем. ❶ path('topics/', views.topics, name='topics'), ] 416 Глава 18 • Знакомство с Django Мы просто добавили topics/ в аргумент регулярного выражения, используемый с URL-адресом домашней страницы . Когда Django проверяет запрашиваемый URL-адрес, эта схема совпадет с любым URL-адресом, который состоит из базового URL-адреса и слова topics . Слеш в конце можно включить, а можно не включать, но после слова topics ничего быть не должно, иначе схема не совпадет. Любой запрос с URL-адресом, соответствующим этой схеме, будет передан функции topics() в views .py Представление topics Функция topics() должна получать данные из базы данных и отправлять их ша- блону. Обновленная версия views .py выглядит так: views.py from django.shortcuts import render ❶ from .models import Topic def index(request): ❷ def topics(request): """Выводит список тем.""" ❸ topics = Topic.objects.order_by('date_added') ❹ context = {'topics': topics} ❹ return render(request, 'learning_logs/topics.html', context) Сначала импортируется модель, связанная с нужными данными . Функции topics() необходим один параметр: объект request , полученный Django от серве- ра . В точке выдается запрос к базе данных на получение объектов Topic , от- сортированных по атрибуту date_added . Полученный итоговый набор сохраняется в topics В точке определяется контекст, который будет передаваться шаблону. Контекст представляет собой словарь, в котором ключами являются имена, используемые в шаблоне для обращения к данным, а значениями — данные, которые должны пере- даваться шаблону. В данном случае существует всего одна пара «ключ-значение», которая содержит набор тем, отображаемых на странице. При построении стра- ницы, использующей данные, функции render() передается переменная context , а также объект request и путь к шаблону . Шаблон topics Шаблон страницы со списком тем получает словарь context , чтобы шаблон мог использовать данные, предоставленные topics() . Создайте файл с именем topics . html в одном каталоге с index .html . Вывод списка тем в шаблоне осуществляется следующим образом: Построение других страниц 417 topics.html {% extends "learning_logs/base.html" %} {% block content %} Topics ❶
❷ {% for topic in topics %} ❸ ❹ {% empty %} ❺ {% endfor %} ❻ {% endblock content %} Сначала тег {% extends %} объявляет о наследовании от base .html , как и в случае с шаблоном index , после чего открывается блок content . Тело страницы содержит маркированный (bulleted) список введенных тем. В стандартном языке HTML мар- кированный список называется неупорядоченным списком и обозначается тегами . Список тем начинается в точке . В точке находится другой шаблонный тег, эквивалентный циклу for , для пере- бора списка topics из словаря context . Код, используемый в шаблоне, отличается от Python некоторыми важными особенностями. Python использует отступы для обозначения строк, входящих в тело цикла. В шаблоне каждый цикл for должен снабжаться явным тегом {% endfor %} , обозначающим конец цикла. Таким образом, в шаблонах часто встречаются циклы следующего вида: {% for элемент in список %} действия для каждого элемента {% endfor %} В цикле каждая тема должна быть преобразована в элемент маркированного спи- ска. Чтобы вывести значение переменной в шаблоне, заключите ее имя в двойные фигурные скобки. Фигурные скобки на странице не появятся; они всего лишь сообщают Django об использовании шаблонной переменной. Код {{ topic }} в точке будет заменен значением topic при каждом проходе цикла. Тег HTML обозначает элемент списка. Все, что находится между тегами, в паре тегов , будет отображаться как элемент маркированного списка. В точке находится шаблонный тег {% empty %} , который сообщает Django, что делать при отсутствии элементов в списке. В нашем примере выводится сообще- ние о том, что темы еще не созданы. Последние две строки завершают цикл for и маркированный список . Затем необходимо изменить базовый шаблон и включить ссылку на страницу с темами. Добавьте следующий код в base .html : 418 Глава 18 • Знакомство с Django base.html ❶ Learning Log - ❷ Topics {% block content %}{% endblock content %} После ссылки на домашнюю страницу добавляется дефис, после которого встав- ляется ссылка на страницу тем, которая также представлена шаблонным тегом {% url %} . Эта строка приказывает Django сгенерировать ссылку, соответствую- щую схеме URL с именем 'topics' в learning_logs/urls .py Обновив домашнюю страницу в браузере, вы увидите ссылку Topics . Щелчок на этой ссылке открывает страницу, похожую на рис. 18.4. Рис. 18.4. Страница со списком тем Страницы отдельных тем Следующим шагом станет создание страницы для вывода информации по одной теме, с названием темы и всеми записями по этой теме. Мы снова определим новую схему URL, напишем представление и создадим шаблон. Кроме того, на странице со списком тем каждый элемент маркированного списка будет преобразован в ссылку на соответствующую страницу отдельной темы. Схема URL для отдельных тем Схема URL для страницы отдельной темы немного отличается от других схем URL, которые встречались нам ранее, потому что в ней используется атрибут id темы Построение других страниц 419 для обозначения запрашиваемой темы. Например, если пользователь хочет про- смотреть страницу с подробной информацией по теме Chess ( id=1 ), эта страница будет иметь URL-адрес http://localhost:8000/topics/1/ . Вот как выглядит схема для этого URL-адреса из learning_logs/urls .py : urls.py urlpatterns = [ # Страница с подробной информацией по отдельной теме path('topics/ ] Рассмотрим строку 'topics/ в этой схеме URL. Первая часть строки сообщает Django, что искать следует URL-адреса, у которых за базовым адресом идет слово topics. Вторая часть строки, / , описывает целое число, заключенное между двумя слешами; это целое число сохраняется в аргу- менте topic_id Когда Django находит URL-адрес, соответствующий этой схеме, вызывается функ- ция представления topic() , в аргументе которой передается значение, хранящееся в topic_id . Значение topic_id используется для получения нужной темы внутри функции. Представление отдельной темы Функция topic() должна получить тему и все связанные с ней записи из базы данных: views.py ❶ def topic(request, topic_id): """Выводит одну тему и все ее записи.""" ❷ topic = Topic.objects.get(id=topic_id) ❸ entries = topic.entry_set.order_by('-date_added') ❹ context = {'topic': topic, 'entries': entries} ❺ return render(request, 'learning_logs/topic.html', context) Это первая функция представления, которой требуется параметр, отличный от объекта request . Функция получает значение, совпавшее с выражением / , и сохраняет его в topic_id . В точке функция get() ис- пользуется для получения темы (по аналогии с тем, как мы это делали в оболочке Django). В точке загружаются записи, связанные с данной темой, и они упоря- дочиваются по значению date_added : знак «минус» перед date_added сортирует результаты в обратном порядке, то есть самые последние записи будут находиться на первых местах. Тема и записи сохраняются в словаре context , который пере- дается шаблону topic .html . 420 Глава 18 • Знакомство с Django ПРИМЕЧАНИЕ Выражения в строках и , обращающиеся к базе данных за кон- кретной информацией, называются запросами . Когда вы пишете подобные запросы для своих проектов, сначала опробуйте их в оболочке Django . Вы сможете проверить результат намного быстрее, чем если напишете представление и шаблон, а затем про- верите результаты в браузере . Шаблон отдельной темы В шаблоне должно отображаться название темы и текст записей. Также необходимо сообщить пользователю, если по теме еще не было сделано ни одной записи: topic.html {% extends 'learning_logs/base.html' %} {% block content %} ❶ Topic: {{ topic }} Entries: ❷
❸ {% for entry in entries %} ❻ {% empty %} {% endfor %} {% endblock content %} Шаблон расширяет base .html , как и для всех страниц проекта. Затем выводится текущая тема из шаблонной переменной {{ topic }} . Переменная topic доступ- на, потому что она включена в словарь context . Затем создается маркированный список со всеми записями по теме ; перебор записей осуществляется так же, как это делалось ранее для тем . С каждым элементом списка связываются два значения: временная метка и пол- ный текст каждой записи. Для временной метки выводится значение атрибута date_added . В шаблонах Django вертикальная черта ( | ) представляет фильтр — функцию, изменяющую значение шаблонной переменной. Фильтр date:'M d, Y H:i' выводит временные метки в формате January 1, 2018 23:00. Следующая строка выводит полное значение text (вместо первых 50 символов каждой запи- си). Фильтр linebreaks следит за тем, чтобы длинный текст содержал разрывы строк в формате, поддерживаемом браузером (вместо блока непрерывного текста). В точке шаблонный тег {% empty %} используется для вывода сообщения об от- сутствии записей. Построение других страниц 421 Ссылки на странице Прежде чем просматривать страницу отдельной темы в браузере, необходимо из- менить шаблон списка тем, чтобы каждая тема вела на соответствующую страницу. Внесите следующие изменения в topics .html : topics.html {% for topic in topics %} {{ topic }} {% empty %} Шаблонный тег URL используется для генерирования ссылки на основании схемы URL из learning_logs с именем 'topic' . Этой схеме URL необходим аргумент topic_id , поэтому в шаблонный тег URL добавляется атрибут topic.id . Теперь каждая тема в списке представляет собой ссылку на страницу темы, например http://localhost:8000/topics/1/ Если теперь обновить страницу тем и щелкнуть на теме, открывается страница, изображенная на рис. 18.5. Рис. 18.5. Страница со списком всех записей по отдельной теме ПРИМЕЧАНИЕ Между topic.id и topic_id существует неочевидное, но важное раз- личие . Выражение topic.id проверяет тему и получает значение соответствующего идентификатора . Переменная topic_id содержит ссылку на этот идентификатор в коде . Если вы столкнетесь с ошибками при работе с идентификаторами, убедитесь в том, что эти выражения используются правильно . 422 Глава 18 • Знакомство с Django УПРАЖНЕНИЯ 18.7. Документация шаблонов: просмотрите документацию по шаблонам Django по адресу https://docs .djangoproject .com/en/2 .2/ref/templates/ . Используйте ее в работе над собственными проектами. 18.8. Страницы Pizzeria: добавьте страницу в проект Pizzeria из упражнения 18.6 (с. 413) с названиями видов пиццы. Свяжите каждое название пиццы со страницей, на которой вы- водится список дополнений к этой пицце. Обязательно примените наследование шабло- нов, чтобы повысить эффективность построения страниц. Итоги В этой главе вы начали осваивать построение веб-приложений с использованием инфраструктуры Django. Вы написали короткую спецификацию проекта, установи- ли Django в виртуальной среде, узнали, как настроить проект, и проверили правиль- ность настройки. Вы узнали, как создать приложение и как определить модели для представления данных в вашем приложении. Также были рассмотрены базы данных и вы узнали, как Django упрощает миграцию баз данных после внесения изменений в модель. Вы научились создавать суперпользователей для административного сайта, а также использовали административный сайт для ввода исходных данных. Также в этой главе была представлена оболочка Django, позволяющая работать с данными проекта в терминальном сеансе. Вы научились определять URL-адреса, создавать функции представления и писать шаблоны для построения страниц сай- та. Наконец, вы применили механизм наследования шаблонов, который упрощает структуру отдельных шаблонов и модификацию сайта по мере развития проекта. В главе 19 мы создадим интуитивно понятные, удобные страницы, на которых пользователи смогут добавлять новые темы и записи, а также редактировать су- ществующие записи без участия административного сайта. Также будет добавлена система регистрации пользователей, чтобы любой пользователь мог создать учет- ную запись и вести свой журнал. Собственно, в этом и заключается сущность веб- приложения — создание функциональности, с которой может взаимодействовать любое количество пользователей. |