Spec-Zone.ru › Django 4.1

Написание вашего первого приложения 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 содержит несколько Choices, а на странице админки не отображаются варианты.

Пока нет.

Есть два способа решить эту проблему. Первый — зарегистрировать 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):

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 в вашей директории проекта (той, которая содержит manage.py). Шаблоны могут находиться в любом месте вашей файловой системы, доступном для 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.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/4.1/intro/tutorial07/

Spec-Zone.ru

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