Написание вашей первой Django-приложения, часть 7
Этот учебник начинается там, где закончился Учебник 6. Мы продолжаем приложение Web-poll и сосредоточимся на настройке автоматически сгенерированного Django-админ-сайта, который мы впервые изучили в Учебнике 2.
Где получить помощь:
Если у вас возникнут трудности с прохождением этого учебника, пожалуйста, перейдите к разделу Получение помощи раздела FAQ.
Настройка формы администрирования
Зарегистрировав модель Question с помощью admin.site.register(Question), Django смог создать представление формы по умолчанию. Часто вам захочется настроить внешний вид и работу формы администрирования. Вы сделаете это, сообщив Django о желаемых параметрах при регистрации объекта.
Давайте посмотрим, как это работает, переупорядочив поля в форме редактирования. Замените строку admin.site.register(Question) на:
from 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() — каждый раз, когда вам нужно изменить параметры администрирования для модели.
Это конкретное изменение помещает «Дату публикации» перед полем «Вопрос»:
Это не впечатляет с двумя полями, но для форм администрирования с десятками полей выбор интуитивного порядка является важным аспектом удобства использования.
И говоря о формах с десятками полей, вы можете разбить форму на наборы полей:
from 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:
from django.contrib import admin from .models import Choice, Question # ... admin.site.register(Choice)
Теперь «Варианты» — доступный параметр в Django-администрировании. Форма «Добавить вариант» выглядит так:
В этой форме поле «Вопрос» — выпадающий список, содержащий все вопросы в базе данных. Django знает, что ForeignKey должен быть представлен в администрировании как поле <select> . В нашем случае на данный момент существует только один вопрос.
Также обратите внимание на ссылку «Добавить ещё» рядом с «Вопрос». Каждый объект со связанными ForeignKey с другим получает это бесплатно. При нажатии на «Добавить ещё» откроется всплывающее окно с формой «Добавить вопрос». Если вы добавите вопрос в этом окне и нажмёте «Сохранить», Django сохранит вопрос в базе данных и динамически добавит его как выбранный вариант в форме «Добавить вариант», которую вы смотрите.
Но, честно говоря, это неэффективный способ добавления Choice в систему. Лучше было бы добавлять несколько вариантов напрямую при создании объекта Question. Давайте это сделаем.
Удалите вызов register() для модели Choice. Затем измените код регистрации Question так:
from 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 на:
class ChoiceInline(admin.TabularInline):
#...
С этим TabularInline (вместо StackedInline) связанные объекты отображаются в более компактном, табличном формате:
Обратите внимание, что есть дополнительный столбец «Удалить?», который позволяет удалять строки, добавленные с помощью кнопки «Добавить ещё», и строки, которые уже были сохранены.
Настройка списка изменений администрирования
Теперь, когда страница администрирования вопроса выглядит хорошо, давайте внесем некоторые изменения на странице «Список изменений» — той, которая отображает все вопросы в системе.
Вот как она выглядит на данный момент:
По умолчанию Django отображает str() каждого объекта. Но иногда было бы полезнее отобразить отдельные поля. Для этого используйте опцию администрирования list_display, которая представляет собой кортеж имён полей, которые будут отображаться в виде столбцов на странице списка изменений для объекта:
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date')
Для большей эффективности включим также метод was_published_recently() из Учебника 2:
class QuestionAdmin(admin.ModelAdmin):
# ...
list_display = ('question_text', 'pub_date', 'was_published_recently')
Теперь страница списка изменений вопросов выглядит так:
Вы можете нажать на заголовки столбцов, чтобы отсортировать по этим значениям — за исключением случая с заголовком was_published_recently , поскольку сортировка по результатам произвольного метода не поддерживается. Также обратите внимание, что заголовок столбца для was_published_recently по умолчанию — это имя метода (с подчёркиваниями, заменёнными пробелами), и что каждая строка содержит строковое представление результата.
Вы можете улучшить это, добавив методу (в polls/models.py) несколько атрибутов, как показано ниже:
class Question(models.Model):
# ...
def was_published_recently(self):
now = timezone.now()
return now - datetime.timedelta(days=1) <= self.pub_date <= now
was_published_recently.admin_order_field = 'pub_date'
was_published_recently.boolean = True
was_published_recently.short_description = 'Published recently?'
Дополнительную информацию об этих свойствах метода см. в 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:
TEMPLATES = [
{
'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 %}
<h1 id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a></h1>
{% 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. Вместо этого вы можете жестко закодировать ссылки на страницы админки для конкретных объектов так, как вам больше всего подходит.
Что дальше?
Урок для начинающих завершается здесь. В то же время вы можете ознакомиться с некоторыми указаниями о том, куда идти дальше.
Если вы знакомы с упаковкой Python и хотите узнать, как превратить приложение опросов в «многоразовое приложение», ознакомьтесь с Расширенный урок: как создавать многоразовые приложения.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.1/intro/tutorial07/