Пишем приложение на Django. Часть 2. Работаем над фронтендом и админкой
Продолжаем писать приложение на фреймворке Django — тюним внешний вид блога, добавляем кнопки и настраиваем админку.
Иллюстрация: Colowgee для Skillbox Media
В первой части урока по Django мы установили фреймворк, написали движок для блогов, определили компоненты записей и научились постить в него записи. Теперь же поработаем над фронтендом: сделаем посты более аккуратными и симпатичными, добавим кнопки для работы с контентом и улучшим UX. Начнём сразу с четвёртого шага — первые три как раз были в предыдущей статье :)
Шаг 4
Работаем над фронтендом: настраиваем отображение записей блога
Записи, которые мы добавили с помощью панели администратора, не будут отображаться на главной странице сайта. Если сейчас запустить сервер, то вы увидите приветственную страницу Django. Исправим это.
Создаём список и настраиваем представления (Views)
В Django есть два подхода к созданию представлений: на основе функций и на основе классов. Они работают одинаково: принимают запрос и возвращают ответ. Разница между ними в том, что представления на основе функций позволяют точнее контролировать работу, но придётся писать больше кода.
Так как мы создаём блог с простой функциональностью, нам будет удобнее использовать представления на основе классов. Это обычный подход при разработке веб-приложений — например, когда необходимо работать с элементами базы данных.
Используя Django, можно применять встроенные типовые представления. Мы выберем подклассы DetailView и ListView, подключив их к модели Entry в файле entries/views.py:
Создаём шаблон (Templates) в Django
В Django HTML-код генерируется автоматически с помощью шаблонов. Это очень удобно, когда нам надо создавать большое количество типового контента — например, записи в блоге.
Важно помнить: Django ожидает, что шаблоны для представлений на основе классов, которые вы только что создали, будут находиться в определённом месте и называться определённым образом. Поэтому создадим вложенные папки для наших шаблонов с правильным месторасположением:
Сейчас этот путь к шаблонам может показаться вам непонятным, но мы специально называем конечную папку так же, как наше приложение: если в будущем вы захотите использовать это приложение в другом проекте, то вам будет легко разобраться, где хранятся шаблоны для этого приложения.
Начнём с создания файла entry_list.html и добавим в него следующее содержимое:
В шаблонах Django можно динамически ссылаться на классы CSS. Если вы посмотрите на <h2>, вы увидите, что к нему добавлен class="{{ entry.date_created|date: 'l' }}». Этот класс используется для отображения временной метки со специальным форматированием. Следовательно, нашему элементу <h2> в качестве класса теперь присвоен день недели — а значит, этот класс можно использовать, чтобы задавать уникальный стиль записям по дням недели. Этим мы займёмся немного позже, когда начнём оформлять блог.
Внутри цикла entry_list мы можем получить доступ ко всем полям модели Entry. Чтобы не загромождать список слишком большим количеством информации, мы будем показывать содержимое только при переходе на страницу записи. Поэтому создадим файл entry_detail.html в папке entries/templates/entries/ и добавим туда следующий код:
Так как этот шаблон работает с отдельными записями в блоге, то мы не используем цикл для прохождения через все существующие записи.
Определяем маршруты (Roots) для наших записей
Чтобы шаблоны работали, нам необходимо связать созданные представления с URL-адресами. Django использует для этого файл urls.py, позволяющий обрабатывать входящие запросы от пользователя в браузере.
Файл urls.py был создан автоматически в папке blog. Однако для нашего приложения Entries нам необходимо снова создать его — теперь уже в папке entries — и добавить маршруты к представлениям EntryListView и EntryDetailView:
Функция path() должна иметь как минимум два аргумента для обоих представлений:
- строковое имя маршрута, который содержит шаблон URL;
- ссылку на представление в виде функции as_view(). Она используется для представлений на основе классов.
Дополнительно можно передать такие аргументы, как kwargs, и явно указать имя. С помощью имени легко ссылаться на представления в проекте Django. Таким образом, даже если потребуется изменить шаблон URL, не придётся обновлять сами шаблоны.
Теперь, когда URL-адреса для приложения записей созданы, нам нужно связать их со списком urlpatterns блога. Откройте файл diary/urls.py и найдите urlpatterns, которые использует наш проект. Сейчас в нём есть только один маршрут к admin/, который добавлен по умолчанию и позволяет нам попасть в панель администратора Django. Чтобы показать записи блога при посещении сайта http://localhost:8000, надо отправить корневой URL в созданное приложение Entries, изменив diary/urls.py:
Теперь запустите сервер и перейдите в панель администратора Django. Создайте любую запись в блоге:
Сохраним её и перейдём на главную страницу блога — http://127.0.0.1:8000.
Отлично! Наши посты отображаются. Попробуем открыть приветственную запись полностью:
Всё работает, но пока посты выглядят как обычный текстовый документ.
Шаг 5
Работаем над внешним видом блога
Блог должен быть привлекательным и удобным для читателей и автора. Чтобы улучшить его внешний вид, создадим базовый шаблон с единым оформлением по адресу entries/templates/entries/base.html:
Особенность Django заключается в том, что при наследовании шаблонов нам не нужно повторять их разметку. Вместо этого мы просто дополняем дочерние шаблоны, а сам фреймворк автоматически объединяет их перед отображением.
Добавляем таблицу стилей
Вставив {% load static %} в начало файла шаблона, мы можем ссылаться на статические файлы с помощью тега шаблона {% static %} и относительного пути к файлу CSS.
Создадим файл diary.css в папке entries/static/css/ и добавим в него такой код:
Редактируем дочерние шаблоны
Теперь свяжем дочерние шаблоны с родительским шаблоном base.html. Для этого обновим entries/templates/entries/entry_list.html, чтобы он выглядел следующим образом:
Изменим и entries/templates/entries/entries_detail.html:
Теперь оба шаблона наследуют HTML-структуру и стиль от родительского шаблона, в том числе стили, указанные в diary.css.
Запустим сервер Django и посмотрим, как изменился наш блог:
Теперь блог выглядит интереснее. Однако добавлять, редактировать или удалять записи через панель администратора Django всё-таки неудобно. Реализуем эту функциональность на самом сайте.
Шаг 6
Добавляем кнопки для работы с контентом
В работе с записями в блоге нам нужны четыре основных операции:
- создать новую запись;
- прочитать запись;
- обновить запись;
- удалить запись.
Все эти действия можно совершить через панель управления, но это неудобно, так как требует открывать дополнительное окно в браузере. Добавим это в веб-интерфейс блога через знакомую нам работу с представлениями, шаблонами и URL.
Добавляем представления
В файле entries/views.py мы уже импортировали ListView и DetailView. Обновим файл, добавив туда новые представления:
На этот раз недостаточно просто связать классы с нашей моделью Entry. Для EntryCreateView и EntryUpdateView мы явно определили, какие поля модели должны отображаться в форме. А для EntryDeleteView этого не требуется, так как мы планируем удалять запись полностью, вне зависимости от её полей.
Кроме этого, необходимо определить, куда перенаправляется пользователь после отправки формы представления. По умолчанию .get_success_url() просто возвращает значение success_url. В EntryUpdateView мы меняем этот метод, указывая entry.id в качестве аргумента ключевого слова. Это позволяет остаться на странице записи после завершения её редактирования. Вместо использования URL-адресов мы задействуем метод reverse_lazy для обращения к ним по имени, указанному в шаблонах.
Создаём шаблоны для каждой задачи
Как и раньше, Django ищет шаблоны с определённым именем:
- для EntryCreateView это entry_form.html;
- для EntryUpdateView это будет entry_update_form.html;
- для EntryDeleteView это entry_confirm_delete.html.
Если Django не найдёт entry_update_form.html, он может использовать entry_form.html в качестве запасного варианта, восстановив запись в том виде, в каком она существовала до редактирования. Мы можем воспользоваться этой особенностью, создав шаблон, который будет обрабатывать оба варианта в entries/templates/entries/, и добавив для них базовую форму отправки:
Когда этот шаблон загружается как CreateView для создания новой записи, форма будет пустой. При нажатии на кнопку «Отмена» откроется список со всеми записями. При загрузке в качестве CreateUpdateView для обновления существующей записи она будет показана с существующим заголовком и содержанием записи. Если нажать кнопку «Отмена», откроется страница записи без внесённых изменений.
Существует несколько способов отображения формы в шаблоне. При использовании {{ form.as_p }}, Django отобразит поля, которые мы определили ранее в представлении, обернув их в абзацы. Обязательно добавляем в форму {% csrf_token %}. Это показывает браузеру, что отправку формы запросил сам пользователь.
Создадим entry_confirm_delete.html в entries/templates/entries/:
Указываем URL
После того как мы создали представления и их шаблоны, необходимо указать маршруты для доступа к ним в веб-интерфейсе. Для этого добавим три дополнительных пути к urlpatterns в entries/urls.py:
Для entry-create требуется только базовый путь создания новой заметки. Как и для созданной ранее entry-detail, для entry-update и entry-delete необходимо указать первичный ключ, чтобы определить, какая запись должна быть обновлена или удалена.
Теперь все базовые функции блога созданы: можно не только просматривать записи, но и создавать новые, обновлять или удалять существующие из веб-интерфейса. Давайте запустим веб-сервер и перейдём на страницу добавления новой записи, чтобы проверить, работает ли наш код:
Всё работает, но для перехода в формы создания, обновления или удаления записей нет кнопок. Исправим это на следующем шаге.
Шаг 7
Делаем блог удобнее для работы
Чтобы создать, изменить или удалить запись, необходимо запомнить соответствующие URL-адреса и ввести их в адресную строку. Это неудобно. Добавим ссылки на наши представления прямо на страницы блога.
Начнём с ссылки на создание новой записи в шаблоне entries/templates/entries/entry_list.html. Откроем файл и в блок {% block content %} добавим следующий код:
Для того чтобы запись можно было быстро редактировать и удалять, добавим код в шаблон entries/templates/entries/entry_detail.html сразу после </article>:
Откроем наш блог и проверим, как всё работает:
Всё получилось! Кнопки в веб-интерфейсе работают.
Что дальше?
Наш блог работает, но в нём есть что доработать: добавить уведомления о создании, редактировании или удалении записей, разрешить администратору отмечать отдельные посты в качестве избранных, сортировать их в произвольном порядке и так далее. Разобраться в этом можно с помощью официальной документации к фреймворку Django.
Также есть много книг, содержащих разные примеры использования фреймворка. Мы рекомендуем три из них:
- Django for Beginners Уильяма Винсента;
- Django for Professionals: Production websites with Python & Django Уильяма Винсента;
- Django Design Patterns and Best Practices Аруна Равиндрана.