Настройка административного сайта Django

DjangoDjangoBeginner
Практиковаться сейчас

💡 Этот учебник переведен с английского с помощью ИИ. Чтобы просмотреть оригинал, вы можете перейти на английский оригинал

Введение

Этот туториал начинается там, где закончился урок Добавление таблицы стилей и изображения. Мы продолжаем работу над веб-опросом и сосредоточимся на настройке автоматически создаваемого административного сайта Django, который мы впервые рассмотрели в уроке Настройка базы данных.


Skills Graph

%%%%{init: {'theme':'neutral'}}%%%% flowchart RL django(("Django")) -.-> django/DatabaseModelsandMigrationsGroup(["Database, Models, and Migrations"]) django(("Django")) -.-> django/UserInterfaceandInteractionGroup(["User Interface and Interaction"]) django(("Django")) -.-> django/DevelopmentandAdministrationToolsGroup(["Development and Administration Tools"]) django/DatabaseModelsandMigrationsGroup -.-> django/models("Models") django/DatabaseModelsandMigrationsGroup -.-> django/databases("Databases") django/DatabaseModelsandMigrationsGroup -.-> django/schemaeditor("SchemaEditor") django/UserInterfaceandInteractionGroup -.-> django/templates("Templates") django/DevelopmentandAdministrationToolsGroup -.-> django/django_admin("Django Admin") django/DevelopmentandAdministrationToolsGroup -.-> django/contrib_packages("Contrib Packages") subgraph Lab Skills django/models -.-> lab-153747{{"Настройка административного сайта Django"}} django/databases -.-> lab-153747{{"Настройка административного сайта Django"}} django/schemaeditor -.-> lab-153747{{"Настройка административного сайта Django"}} django/templates -.-> lab-153747{{"Настройка административного сайта Django"}} django/django_admin -.-> lab-153747{{"Настройка административного сайта Django"}} django/contrib_packages -.-> lab-153747{{"Настройка административного сайта Django"}} end

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

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

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

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

Запустите сервер разработки Django:

cd ~/project/mysite
python manage.py runserver

Откройте http://127.0.0.1:8000/admin/ в Firefox в рабочей среде и нажмите на ссылку "Questions" (Вопросы). Форма должна выглядеть так:

В данном случае порядок следования полей изменился, и поле "Publication date" (Дата публикации) теперь отображается перед полем "Question" (Вопрос):

Изменение порядка полей в форме административного интерфейса

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

Если же речь идет о формах с большим количеством полей, вы, возможно, захотите разбить форму на группы полей (fieldset):

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)

Первый элемент каждого кортежа в ~django.contrib.admin.ModelAdmin.fieldsets — это заголовок группы полей. Вот, как наша форма выглядит теперь:

Форма административного интерфейса с группами полей

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

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

Ещё не отображаются.

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

from django.contrib import admin

from.models import Choice, Question

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

Теперь "Choices" (Варианты ответов) доступен в административном интерфейсе Django. Форма "Добавить вариант ответа" выглядит так:

Интерфейс формы "Добавить вариант ответа"

В этой форме поле "Question" (Вопрос) представляет собой выпадающий список, содержащий все вопросы из базы данных. Django знает, что ~django.db.models.ForeignKey должен быть представлен в административном интерфейсе в виде <select> (выпадающего списка). В нашем случае на данный момент существует только один вопрос.

Обратите внимание на ссылку "Add another question" (Добавить другой вопрос) рядом с полем "Question". Каждый объект, имеющий отношение ForeignKey к другому объекту, получает такую ссылку бесплатно. Когда вы нажимаете на "Add another question", вы получите всплывающее окно с формой "Добавить вопрос". Если вы добавите вопрос в этом окне и нажмете "Save" (Сохранить), 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 — и каждый раз, когда вы возвращаетесь на страницу "Изменить" для уже созданного объекта, вы получаете ещё три дополнительных места.

В конце трёх текущих мест вы увидите ссылку "Add another Choice" (Добавить другой вариант ответа). Если вы нажмете на неё, будет добавлено новое место. Если вы хотите удалить добавленное место, вы можете нажать на крестик в правом верхнем углу добавленного места. На этом изображении показано добавленное место:

Динамически добавленное дополнительное место

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

class ChoiceInline(admin.TabularInline):
  ...

При использовании TabularInline (вместо StackedInline) связанные объекты отображаются в более компактном, табличном формате:

Табличное отображение вложенных вариантов ответов

Обратите внимание, что есть дополнительный столбец "Delete?" (Удалить?), который позволяет удалить строки, добавленные с помощью кнопки "Add another Choice" (Добавить другой вариант ответа), а также строки, которые уже были сохранены.

Настройка списка объектов для изменения в административном интерфейсе

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

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

Страница списка объектов для изменения в приложении Polls

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

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

Для дополнительного улучшения давайте также добавим метод was_published_recently() из раздела Настройка базы данных:

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

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

Представление списка вопросов для изменения

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

Вы можете улучшить это, используя декоратор ~django.contrib.admin.display для этого метода (в 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

Для получения дополнительной информации о настройках, доступных через декоратор, см. ~django.contrib.admin.ModelAdmin.list_display.

Откройте снова файл polls/admin.py и добавьте улучшение на страницу списка вопросов для изменения: фильтры, используя ~django.contrib.admin.ModelAdmin.list_filter. Добавьте следующую строку в QuestionAdmin:

list_filter = ["pub_date"]

Это добавит боковую панель "Фильтр", которая позволяет пользователям фильтровать список объектов для изменения по полю pub_date:

Боковая панель фильтра в административном интерфейсе

Тип фильтра, отображаемого, зависит от типа поля, по которому вы фильтруете. Поскольку pub_date является ~django.db.models.DateTimeField, Django знает, что нужно предоставить соответствующие варианты фильтрации: "Любая дата", "Сегодня", "Последние 7 дней", "Этот месяц", "Этот год".

Все это выглядит хорошо. Добавим поиск:

search_fields = ["question_text"]

Это добавит поле поиска в верхней части списка объектов для изменения. Когда пользователь вводит поисковые запросы, Django будет искать по полю question_text. Вы можете использовать столько полей, сколько хотите — хотя, поскольку幕后使用 LIKE запрос, ограничение количества полей поиска до разумного числа упростит поиск в базе данных.

Теперь также стоит отметить, что списки объектов для изменения предоставляют автоматическую постраничность. По умолчанию на каждой странице отображается 100 элементов. Постраничность списка объектов для изменения <django.contrib.admin.ModelAdmin.list_per_page>, поля поиска <django.contrib.admin.ModelAdmin.search_fields>, фильтры <django.contrib.admin.ModelAdmin.list_filter>, иерархия дат <django.contrib.admin.ModelAdmin.date_hierarchy> и упорядочивание заголовков столбцов <django.contrib.admin.ModelAdmin.list_display> все работают так, как вы ожидаете.

Настройка внешнего вида административного интерфейса

Очевидно, что наличие надписи "Django administration" (Администрирование Django) вверху каждой страницы административного интерфейса выглядит нелепо. Это всего лишь текст-заполнитель.

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

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

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

Откройте файл настроек (mysite/settings.py, помните), и добавьте параметр DIRS <TEMPLATES-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 <TEMPLATES-DIRS> — это список директорий файловой системы, которые будут проверяться при загрузке шаблонов Django; это путь поиска.

Организация шаблонов

Точно так же, как и статические файлы, мы могли бы иметь все наши шаблоны вместе, в одной большой директории templates, и это работало бы прекрасно. Однако шаблоны, относящиеся к определенному приложению, должны быть помещены в директорию шаблонов этого приложения (например, polls/templates), а не в директорию проекта (templates). Мы обсудим в более подробностях в уроке о модульных приложениях </intro/reusable-apps> почему мы это делаем.

Теперь создайте директорию под названием admin внутри templates, и скопируйте шаблон admin/base_site.html из стандартной директории шаблонов административного интерфейса в исходном коде Django (django/contrib/admin/templates) в эту директорию.

Где находятся исходные файлы Django?

Если у вас возникают трудности с поиском расположения исходных файлов Django на вашей системе, запустите следующую команду:

python -c "import django; print(django.__path__)"
['/home/labex/.local/lib/python3.10/site-packages/django']

Затем отредактируйте файл и замените {{ site_header|default:_('Django administration') }} (включая фигурные скобки) на имя вашего сайта, как вам будет уместно. В итоге у вас должно получиться раздел кода, похожий на:

{% block branding %}
<div id="site-name"><a href="{% url 'admin:index' %}">Polls Administration</a><div>
{% endblock %}

Мы используем этот подход, чтобы показать вам, как переопределить шаблоны. В реальном проекте вы, вероятно, бы использовали атрибут django.contrib.admin.AdminSite.site_header, чтобы более легко произвести данную настройку.

В этом файле шаблона содержится много текста, подобного {% block branding %} и {{ title }}. Теги {% и {{ являются частью языка шаблонов Django. Когда Django рендерит admin/base_site.html, этот язык шаблонов будет оцениваться, чтобы сформировать окончательную HTML-страницу, точно так же, как мы видели в разделе **Создание представлений для публичного интерфейса**.

Обратите внимание, что любой стандартный шаблон административного интерфейса Django может быть переопределен. Чтобы переопределить шаблон, сделайте то же, что и с base_site.html — скопируйте его из стандартной директории в вашу собственную директорию и внесите изменения.

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

Бережливые читатели спросят: Но если DIRS <TEMPLATES-DIRS> по умолчанию был пустым, как Django находил стандартные шаблоны административного интерфейса? Ответ заключается в том, что, так как APP_DIRS <TEMPLATES-APP_DIRS> установлен в True, Django автоматически ищет поддиректорию templates/ внутри каждого пакета приложения, для использования в качестве резервного варианта (не забывайте, что django.contrib.admin — это приложение).

Наше приложение для опросов не очень сложно и не требует собственных шаблонов административного интерфейса. Однако, если оно стало более сложным и потребовало модификации стандартных шаблонов административного интерфейса для некоторых его функций, было бы более разумным изменить шаблоны приложения, а не шаблоны проекта. Таким образом, вы могли бы включить приложение для опросов в любой новый проект и быть уверены, что оно найдет нужные ему собственные шаблоны.

Подробнее о том, как Django находит свои шаблоны, см. в документации по загрузке шаблонов <template-loading>.

Настройка главной страницы административного интерфейса

В аналогичном духе вы, возможно, захотите настроить внешний вид и удобство использования главной страницы административного интерфейса Django.

По умолчанию на ней отображаются все приложения из INSTALLED_APPS, которые были зарегистрированы с административным приложением, в алфавитном порядке. Возможно, вы захотите внести существенные изменения в макет. Ведь главная страница административного интерфейса, вероятно, является самой важной, и она должна быть простой в использовании.

Шаблон для настройки — admin/index.html. (Делайте то же, что и с admin/base_site.html в предыдущем разделе — скопируйте его из стандартной директории в вашу собственную директорию шаблонов). Откройте файл, и вы увидите, что он использует переменную шаблона под названием app_list. Эта переменная содержит все установленные в Django приложения. Вместо этого вы можете жестко закодировать ссылки на страницы административного интерфейса, специфичные для объектов, любым способом, который вам кажется наиболее подходящим.

Резюме

Поздравляем! Вы завершили лабораторную работу по настройке административного сайта Django. Вы можете практиковаться в других лабораторных работах в LabEx, чтобы улучшить свои навыки.