Spec-Zone.ru › Django 3.0

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

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

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

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

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

Зарегистрировав модель Question с помощью admin.site.register(Question), 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 по умолчанию — имя метода (с заменой подчеркиваний на пробелы), а каждая строка содержит строковое представление результата.

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

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:

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

Вы можете это изменить, используя систему шаблонов 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': [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__)"
...\> 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.0/intro/tutorial07/

Spec-Zone.ru

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