Написание вашей первой Django-приложения, часть 7
Этот учебник начинается там, где закончился Учебник 6. Мы продолжаем приложение web-опроса и сосредоточимся на настройке автоматически сгенерированного административного сайта Django, который мы впервые изучали в Учебнике 2.
Где получить помощь:
Если у вас возникли проблемы с этим учебником, перейдите к разделу Получение помощи раздела FAQ.
Настройка формы администратора
Зарегистрировав модель Question с помощью admin.site.register(Question), Django смог создать форму представления по умолчанию. Часто вам потребуется настроить внешний вид и работу формы администратора. Для этого вы сообщите Django о желаемых параметрах при регистрации объекта.
Давайте посмотрим, как это работает, переупорядочив поля в форме редактирования. Замените строку admin.site.register(Question) на:
polls/admin.pyfrom django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fields = ["pub_date", "question_text"]
admin.site.register(Question, QuestionAdmin)
Вы будете следовать этому шаблону – создавайте класс администратора модели, а затем передавайте его в качестве второго аргумента в admin.site.register() – каждый раз, когда вам нужно изменить параметры администратора для модели.
Это конкретное изменение выше помещает «Дату публикации» перед полем «Вопрос»:
Это не впечатляет с двумя полями, но для форм администратора с десятками полей выбор интуитивного порядка – важная деталь удобства использования.
И говоря о формах с десятками полей, вы можете разделить форму на группы полей:
polls/admin.pyfrom django.contrib import admin
from .models import Question
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"]}),
]
admin.site.register(Question, QuestionAdmin)
Первый элемент каждой кортежи в fieldsets – это заголовок группы полей. Вот как выглядит наша форма сейчас:
Добавление связанных объектов
Пока нет.
Существует два способа решения этой проблемы. Первый – зарегистрировать Choice в администраторе так же, как мы сделали с Question:
polls/admin.pyfrom django.contrib import admin from .models import Choice, Question # ... admin.site.register(Choice)
Теперь «Варианты» – доступный вариант в Django администраторе. Форма «Добавить вариант» выглядит так:
В этой форме поле «Вопрос» – выпадающий список, содержащий все вопросы в базе данных. Django знает, что ForeignKey должен быть представлен в администраторе как поле <select> . В нашем случае на данный момент существует только один вопрос.
Обратите также внимание на ссылку «Добавить еще один вопрос» рядом с «Вопрос». Каждый объект со связью ForeignKey с другим объектом получает это бесплатно. Когда вы нажмёте «Добавить ещё один вопрос», откроется всплывающее окно с формой «Добавить вопрос». Если вы добавите вопрос в этом окне и нажмёте «Сохранить», Django сохранит вопрос в базе данных и динамически добавит его как выбранный вариант в форме «Добавить вариант», которую вы смотрите.
Но, честно говоря, это неэффективный способ добавления Choice объектов в систему. Лучше было бы добавить сразу несколько вариантов при создании Question объекта. Давайте сделаем это.
Удалите вызов register() для модели Choice. Затем отредактируйте код регистрации Question так, чтобы он выглядел следующим образом:
polls/admin.pyfrom django.contrib import admin
from .models import Choice, Question
class ChoiceInline(admin.StackedInline):
model = Choice
extra = 3
class QuestionAdmin(admin.ModelAdmin):
fieldsets = [
(None, {"fields": ["question_text"]}),
("Date information", {"fields": ["pub_date"], "classes": ["collapse"]}),
]
inlines = [ChoiceInline]
admin.site.register(Question, QuestionAdmin)
Это говорит Django: «Choice объекты редактируются на странице администратора Question. По умолчанию предоставьте достаточное количество полей для 3 вариантов.»
Загрузите страницу «Добавить вопрос», чтобы увидеть, как это выглядит:
Это работает так: есть три слота для связанных вариантов – как указано в extra, – и каждый раз, когда вы возвращаетесь на страницу «Изменить» для уже созданного объекта, вы получаете ещё три дополнительных слота.
В конце трёх текущих слотов вы найдёте ссылку «Добавить ещё один вариант». Если вы нажмёте на неё, будет добавлен новый слот. Если вы хотите удалить добавленный слот, вы можете нажать на X в правом верхнем углу добавленного слота. На этом изображении показан добавленный слот:
Однако есть небольшая проблема. Для отображения всех полей для ввода связанных Choice объектов требуется много места на экране. По этой причине Django предлагает табличный способ отображения связанных объектов. Для его использования измените объявление ChoiceInline на:
polls/admin.pyclass ChoiceInline(admin.TabularInline): ...
С помощью этого TabularInline (вместо StackedInline), связанные объекты отображаются в более компактном, табличном формате:
Обратите внимание, что есть дополнительный столбец «Удалить?», который позволяет удалять строки, добавленные с помощью кнопки «Добавить ещё один вариант», и строки, которые уже были сохранены.
Настройка списка изменений администратора
Теперь, когда страница администратора «Вопрос» выглядит хорошо, давайте внесём некоторые изменения на странице «Список изменений» – той, которая отображает все вопросы в системе.
Вот как она выглядит на данный момент:
По умолчанию Django отображает str() каждого объекта. Но иногда было бы полезнее отобразить отдельные поля. Для этого используйте опцию администратора list_display, которая представляет собой кортеж имён полей, которые должны отображаться в виде столбцов на странице списка изменений объекта:
polls/admin.pyclass QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ["question_text", "pub_date"]
Для полноты картины добавим метод was_published_recently() из Учебника 2:
polls/admin.pyclass QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ["question_text", "pub_date", "was_published_recently"]
Теперь страница списка изменений вопроса выглядит так:
Вы можете нажать на заголовки столбцов, чтобы отсортировать по этим значениям, за исключением заголовка was_published_recently, так как сортировка по выводу произвольного метода не поддерживается. Также обратите внимание, что заголовок столбца для was_published_recently по умолчанию – имя метода (с подчёркиваниями, заменёнными пробелами), и каждая строка содержит строковое представление вывода.
Вы можете улучшить это, используя декоратор display() для этого метода (в polls/models.py), как показано ниже:
polls/models.pyfrom django.contrib import admin
class Question(models.Model):
# ...
@admin.display(
boolean=True,
ordering="pub_date",
description="Published recently?",
)
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
Дополнительную информацию о свойствах, настраиваемых с помощью декоратора, см. в list_display.
Отредактируйте файл polls/admin.py ещё раз и добавьте улучшение к странице списка изменений Question: фильтры с помощью list_filter. Добавьте следующую строку в QuestionAdmin:
list_filter = ["pub_date"]
Это добавляет боковую панель «Фильтр», которая позволяет пользователям фильтровать список изменений по полю pub_date:
Тип отображаемого фильтра зависит от типа поля, по которому вы фильтруете. Так как pub_date является DateTimeField, Django знает, как предоставить соответствующие параметры фильтра: «Любая дата», «Сегодня», «Последние 7 дней», «Этот месяц», «Этот год».
Это хорошо получается. Давайте добавим возможность поиска:
search_fields = ["question_text"]
Это добавляет поле поиска в верхней части списка изменений. Когда кто-то вводит поисковые термины, Django будет искать по полю question_text. Вы можете использовать любое количество полей, хотя, поскольку он использует запрос LIKE в фоновом режиме, ограничение числа полей поиска до разумного числа упростит выполнение поиска вашей базе данных.
Теперь также стоит отметить, что списки изменений предоставляют вам страницу разбивки по страницам. По умолчанию отображается 100 элементов на странице. Change list pagination, search boxes, filters, date-hierarchies и column-header-ordering работают вместе так, как вы ожидаете.
Настройка внешнего вида администратора
Очевидно, иметь «Администрирование Django» в верхней части каждой страницы администратора – нелепо. Это просто заполняющий текст.
Вы можете изменить его, используя систему шаблонов Django. Django-админка работает на Django, а её интерфейсы используют собственную систему шаблонов Django.
Настройка шаблонов вашего проекта
Создайте директорию templates в каталоге вашего проекта (том, который содержит manage.py). Шаблоны могут находиться где угодно в вашей файловой системе, к которой может получить доступ Django. (Django работает под учетной записью пользователя, под которой работает ваш сервер.) Однако, хорошее соглашение — держать шаблоны внутри проекта.
Откройте файл настроек (mysite/settings.py, помните) и добавьте параметр DIRS в настройку TEMPLATES:
mysite/settings.pyTEMPLATES = [
{
"BACKEND": "django.template.backends.django.DjangoTemplates",
"DIRS": [BASE_DIR / "templates"],
"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",
],
},
},
]
DIRS — это список каталогов файловой системы, которые нужно проверить при загрузке шаблонов Django; это путь поиска.
Организация шаблонов
Как и статические файлы, все наши шаблоны можно собрать в один большой каталог шаблонов, и это будет работать. Однако, шаблоны, относящиеся к конкретному приложению, должны размещаться в директории шаблонов этого приложения (например, polls/templates) вместо каталога проекта (templates). Мы подробнее обсудим это в учебнике по многократно используемым приложениям (почему мы так делаем).
Теперь создайте директорию admin внутри templates и скопируйте шаблон admin/base_site.html из каталога шаблонов по умолчанию Django-админки в исходном коде самого Django (django/contrib/admin/templates) в эту директорию.
Где находятся исходные файлы Django?
Если вам сложно найти исходные файлы Django на вашей системе, выполните следующую команду:
$ python -c "import django; print(django.__path__)"
...\> py -c "import django; print(django.__path__)"
Затем отредактируйте файл и замените {{ site_header|default:_('Django administration') }} (включая фигурные скобки) на имя вашего сайта по своему усмотрению. В итоге у вас должен получиться кусок кода, подобный:
{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></div>
{% if user.is_anonymous %}
{% include "admin/color_theme_toggle.html" %}
{% endif %}
{% endblock %}
Мы используем этот подход, чтобы показать вам, как переопределять шаблоны. В реальном проекте вы, вероятно, будете использовать атрибут django.contrib.admin.AdminSite.site_header, чтобы проще сделать данную настройку.
Этот файл шаблона содержит много текста, например {% block branding %} и {{ title }}. Теги {% и {{ — часть языка шаблонов Django. При отрисовке Django admin/base_site.html, этот язык шаблонов будет вычислен, чтобы создать окончательную страницу HTML, как мы видели в уроке 3.
Обратите внимание, что любой из шаблонов по умолчанию Django-админки можно переопределить. Для переопределения шаблона сделайте то же самое, что и с base_site.html — скопируйте его из каталога по умолчанию в ваш пользовательский каталог и внесите изменения.
Настройка шаблонов вашего приложения
Внимательные читатели спросят: Но если DIRS по умолчанию было пустым, как Django находил шаблоны по умолчанию админки? Ответ в том, что, так как APP_DIRS установлено в True, Django автоматически ищет подкаталог templates/ в каждом пакете приложения, чтобы использовать его в качестве резервного варианта (не забудьте, что django.contrib.admin — приложение).
Наше приложение опросов не очень сложное и не нуждается в кастомизации шаблонов админки. Но если оно станет более сложным и потребуется изменить стандартные шаблоны админки Django для некоторых его функций, будет разумнее изменить шаблоны приложения, а не проекта. Таким образом, вы можете включить приложение опросов в любой новый проект и быть уверены, что оно найдет необходимые кастомизированные шаблоны.
См. документацию по загрузке шаблонов для получения дополнительной информации о том, как Django находит свои шаблоны.
Настройка главной страницы админки
В той же связи, вы можете настроить внешний вид главной страницы Django-админки.
По умолчанию она отображает все приложения в INSTALLED_APPS, зарегистрированные с приложением админки, в алфавитном порядке. Вам может потребоваться существенно изменить её структуру. В конце концов, главная страница админки, вероятно, самая важная, и она должна быть удобной в использовании.
Шаблон для настройки — admin/index.html. (Сделайте то же самое, что и с admin/base_site.html в предыдущем разделе — скопируйте его из каталога по умолчанию в ваш пользовательский каталог шаблонов). Откройте файл, и вы увидите, что он использует переменную шаблона app_list. Эта переменная содержит все установленные приложения Django. Вместо этого вы можете вписать ссылки на страницы админки конкретных объектов так, как сочтёте нужным.
Когда вы освоитесь с админкой, прочитайте часть 8 этого руководства, чтобы узнать, как использовать сторонние пакеты.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/5.0/intro/tutorial07/