Написание вашего первого приложения Django, часть 7
Этот учебник начинается там, где Учебник 6 закончился. Мы продолжаем приложение Web-poll и сосредоточимся на настройке автоматически сгенерированной Django-админской панели, которую мы впервые изучили в Учебнике 2.
Настройка формы админки
Зарегистрировав модель 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 — это заголовок набора полей. Вот как выглядит наша форма сейчас:

Добавление связанных объектов
Хорошо, у нас есть страница админки для вопросов, но у Question есть несколько Choice, а страница админки не отображает варианты.
Пока нет.
Есть два способа решить эту проблему. Первый — зарегистрировать 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': [os.path.join(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__)"
Затем просто отредактируйте файл и замените {{ 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/1.9/intro/tutorial07/