Spec-Zone.ru › Django 5.2

Написание вашего первого приложения Django, часть 7

Это учебное пособие начинается там, где закончилось Учебное пособие 6. Мы продолжаем веб-приложение для опросов и сосредоточимся на настройке автоматически сгенерированной Django панели администратора, которую мы впервые изучили в Учебном пособии 2.

Где получить помощь:

Если у вас возникли проблемы с прохождением данного учебного пособия, обратитесь к разделу Получение помощи раздела FAQ.

Настройка формы администратора

Зарегистрировав модель Question с помощью admin.site.register(Question), Django смог создать стандартное представление формы. Часто вам потребуется настроить внешний вид и работу формы администратора. Вы сделаете это, указав необходимые параметры Django при регистрации объекта.

Давайте посмотрим, как это работает, переупорядочив поля в форме редактирования. Замените строку admin.site.register(Question) на:

polls/admin.py
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() — каждый раз, когда вам нужно изменить параметры администратора для модели.

Это изменение помещает поле «Дата публикации» перед полем «Вопрос»:

Fields have been reordered

Это не впечатляет с двумя полями, но для форм администратора с десятками полей выбор интуитивного порядка является важным аспектом удобства использования.

И говоря о формах с десятками полей, вы можете разбить форму на группы полей:

polls/admin.py
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 — это заголовок группы полей. Вот как сейчас выглядит наша форма:

Form has fieldsets now

Добавление связанных объектов

Хорошо, у нас есть страница администратора для вопроса, но у Question есть несколько Choice, а на странице администратора не отображаются варианты.

Пока нет.

Есть два способа решения этой проблемы. Первый — зарегистрировать Choice в администраторе так же, как мы сделали с Question:

polls/admin.py
from django.contrib import admin

from .models import Choice, Question

# ...
admin.site.register(Choice)

Теперь «Варианты» — доступный параметр в Django администраторе. Форма «Добавить вариант» выглядит так:

Choice admin page

В этой форме поле «Вопрос» представляет собой выпадающий список, содержащий каждый вопрос в базе данных. Django знает, что ForeignKey должен быть представлен в администраторе как поле <select>. В нашем случае пока существует только один вопрос.

Также обратите внимание на ссылку «Добавить ещё один вопрос» рядом с «Вопрос». Каждый объект с отношением ForeignKey к другому получает это бесплатно. При нажатии на «Добавить ещё один вопрос» откроется всплывающее окно с формой «Добавить вопрос». Если вы добавите вопрос в этом окне и нажмёте «Сохранить», Django сохранит вопрос в базе данных и динамически добавит его как выбранный вариант в форме «Добавить вариант», которую вы сейчас видите.

Но на самом деле это неэффективный способ добавления Choice объектов в систему. Лучше было бы добавить сразу несколько вариантов при создании Question объекта. Давайте это сделаем.

Удалите вызов register() для модели Choice. Затем отредактируйте код регистрации Question, чтобы он стал таким:

polls/admin.py
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 вариантов».

Загрузите страницу «Добавить вопрос», чтобы увидеть, как это выглядит:

Add question page now has choices on it

Это работает так: есть три слота для связанных вариантов — как указано в extra — и каждый раз, когда вы возвращаетесь на страницу «Изменить» для уже созданного объекта, вы получаете ещё три дополнительных слота.

В конце трёх текущих слотов вы найдёте ссылку «Добавить ещё один вариант». Если вы нажмёте на неё, будет добавлен новый слот. Если вы хотите удалить добавленный слот, вы можете нажать на X в правом верхнем углу добавленного слота. На этом изображении показан добавленный слот:

Additional slot added dynamically

Однако есть одна небольшая проблема. Для отображения всех полей для ввода связанных Choice объектов требуется много места на экране. Поэтому Django предлагает табличный способ отображения связанных объектов. Для его использования измените объявление ChoiceInline, чтобы оно стало таким:

polls/admin.py
class ChoiceInline(admin.TabularInline): ...

С этим TabularInline (вместо StackedInline) связанные объекты отображаются в более компактном формате таблицы:

Add question page now has more compact choices

Обратите внимание на дополнительный столбец «Удалить?», который позволяет удалять строки, добавленные с помощью кнопки «Добавить ещё один вариант», и строки, которые уже были сохранены.

Настройка списка изменений администратора

Теперь, когда страница администратора для вопроса выглядит хорошо, давайте внесём некоторые изменения на страницу «Список изменений» — той, которая отображает все вопросы в системе.

Вот как она выглядит сейчас:

Polls change list page

По умолчанию Django отображает str() каждого объекта. Но иногда было бы полезнее отобразить отдельные поля. Для этого используйте параметр администратора list_display, который представляет собой список имён полей для отображения в виде столбцов на странице списка изменений для объекта:

polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date"]

Для большей наглядности, давайте также включим метод was_published_recently() из Учебного пособия 2:

polls/admin.py
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ["question_text", "pub_date", "was_published_recently"]

Теперь страница списка изменений для вопроса выглядит так:

Polls change list page, updated

Вы можете нажать на заголовки столбцов, чтобы отсортировать по этим значениям — за исключением заголовка was_published_recently, потому что сортировка по результату произвольного метода не поддерживается. Также обратите внимание, что заголовок столбца для was_published_recently по умолчанию — это имя метода (с подчёркиваниями, заменёнными пробелами), и что каждая строка содержит строковое представление результата.

Вы можете улучшить это, используя декоратор display() для этого метода (расширяя файл polls/models.py, созданный в Учебном пособии 2), как показано ниже:

polls/models.py
from 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:

Polls change list page, updated

Тип отображаемого фильтра зависит от типа поля, по которому вы фильтруете. Поскольку 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 administration» вверху каждой страницы админки — абсурд. Это просто текст-заполнитель.

Однако вы можете изменить это, используя систему шаблонов Django. Django админка работает на Django, а её интерфейсы используют собственную систему шаблонов Django.

Настройка шаблонов проекта

Создайте директорию templates в вашей директории djangotutorial. Шаблоны могут находиться в любой доступной для Django части вашей файловой системы. (Django работает как пользователь, под которым запущен ваш сервер.) Однако хорошей практикой является хранение шаблонов внутри проекта.

Откройте файл настроек (mysite/settings.py, помните) и добавьте параметр DIRS в настройку TEMPLATES:

mysite/settings.py
TEMPLATES = [
    {
        "BACKEND": "django.template.backends.django.DjangoTemplates",
        "DIRS": [BASE_DIR / "templates"],
        "APP_DIRS": True,
        "OPTIONS": {
            "context_processors": [
                "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.2/intro/tutorial07/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API