Django: пример создания приложения – часть 3: панель управления

Автор: | 14/05/2015

django_logo_2Предыдущая часть – Django: пример создания приложения – часть 2: создание и работа с database API

Создание суперпользователя

Для начала – нам необходимо создать пользователя, который сможет входить в админпанель.

Выполните следующую команду:

$ python manage.py createsuperuser
Username (leave blank to use 'setevoy'):
Email address: [email protected]
Password:
Password (again):
Superuser created successfully.

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

Админпанель Django активирована по умолчанию. Давайте запустим сервер разработки и посмотрим её:

$ python manage.py runserver 77.***.***.20:8000

Теперь – откройте браузер, и перейдите по адресу http://ваш_IP:8000/admin/. Вы должны увидеть окно входа в панель управления:

django_2

Теперь – войдите в панель управления, используя логин и пароль, которые вы создали в начале. Вы должны увидеть главную страницу панели управления:

django_3

Вы должны увидеть две группы содержимого, доступного для редактирования – Группы (Groups)  и Пользователи (Users). Они предоставляются фреймворком авторизации django.contrib.auth.

Добавление приложения в админпанель

Сейчас ваше приложение – Question – не отображается в панели управления.

Что бы добавить его туда – нам необходимо указать админпанели, что приложение Questions тоже имеет интерфейс администрирования. Что бы сделать это – отредактируйте файл polls/admin.py в который добавьте такой код:

from django.contrib import admin

from .models import Question

admin.site.register(Question)

Обзор функционала панели управления

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

django_4

Нажмите на “Questions” – и вы попадёте в “список изменений” (change list) для ваших вопросов.

Тут отображаются все созданные вами вопросы из базы данных, и можно выбрать какой из них редактировать. Вот вопрос “What’s up?”, который создали в предыдущей части:

django_5

Нажмите на него для редактирования:

django_6

Вот на что тут стоит обратить внимание:

  • форма сгенерирована автоматически из модели Question;
  • различные типы данных модели (DateTimeFieldCharField) соответствуют подходящему HTML-виджету ввода данных ; каждый тип данных знает, как ему отобразить себя в панели управления Django;
  • каждый элемент DateTimeField имеет JavaScript ссылку; у дат есть ссылка Today и всплывающее окно календаря, а у поля времени – ссылка “сейчас” и всплывающее окно с наиболее используемыми временными данными.

Нижняя часть страницы предоставляет вам такие опции:

  • Save – сохранить изменения и вернуться на предыдущую страницу к списку изменений;
  • Save and continue editing – сохранить изменения, и перезагрузить страницу редактируемого объекта;
  • Save and add another – сохранить изменения, и загрузить новую пустую страницу для создания аналогичного объекта;
  • Delete – отобразит страницу подтверждения удаления.

Измените “Date published“, кликнув на Today и Now. Затем – нажмите Save and continue editing,а потом – History, справа вверху. Вы увидите страницу, на которой будут отображены все изменения, сделанные с этим объектом через панель управления Django, с указанием времени и имени пользователя, который их выполнил:

django_7

Изменение отображения форм в админпанели

Задумайтесь на минуту – написания какого количества кода вам удалось избежать. После регистрации 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().

В данном случае мы изменили порядок отображения – теперь Publication date будет выводиться перед Question:

django_8

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

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

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 – это заголовок группы. Вот как наша форма будет выглядеть теперь:

django_9

Вот можете так же назначать HTML классы для каждого поля. Например, Django предоставляет класс “collapse“, который отображает связанное с ним поле свёрнутым.

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

from django.contrib import admin

from .models import Question

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]

admin.site.register(Question, QuestionAdmin)

django_10

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

ОК, у нас есть страничка Question в панель и управления. Но у Question – есть множественные Choices (варианты ответов), и админпанель их пока не отображает.

Есть два способа решить эту задачу. Первый – просто зарегистрировать Choice , как мы это сделали с Question – в файле polls/admin.py:

from django.contrib import admin

from .models import Choice, Question

class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]

admin.site.register(Question, QuestionAdmin)
admin.site.register(Choice)

Теперь Choice доступны в панели управления:

django_11

django_12

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

Обратите так же внимание на +, который является ссылкой на добавление нового вопроса. Если вы нажмёте на Add Another Question – у вас появится всплывающее окно с формой добавления нового вопроса. Если вы добавите тут новый вопрос – Django сохранит его в базе, и добавит к списку доступных вопросов.

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

Удалите admin.site.register(Choice) из файла polls/admin.py, и отредактируйте код 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 поля для вариантов ответа“.

Перейдите на страницу Add question и посмотрите – как это будет выглядеть:

django_13

Вот как это работает: у нас есть три слота для связанных Choice – как указано параметром extra – и каждый раз, когда вы возвращаетесь к странице редактирования – вы будет видеть три дополнительных поля для вариантов ответа.

В конце списка вариантов ответа – вы увидите ссылку на добавление ещё одного варианта – Add another Choice. Если кликнуть на него – будет добавлено ещё оно поле. Если вы хотите удалить его – можно кликнуть на крестик справа вверху поля, но вы не сможете удалить первые три поля.

Вот как это выглядит:

django_14

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

class ChoiceInline(admin.TabularInline):
    model = Choice
    extra = 3

Используя метод TabularInline вместо StackedInline – связанные объекты будут отображаться более компактно:

django_15

Настройка списка редактирования

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

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

django_16

По умолчанию – Django отображает str() каждого объекта. Но иногда может потребоваться отобразить отдельные поля. Что бы сделать это – используйте опцию админпанели list_display, которая является кортежем, содержащим поля для отображения. Отредактируйте файл polls/admin.py:

...
class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date')
...

Давайте так же включим сюда дополнительное поле was_published_recently, которое мы создали в предыдущей части:

...
class QuestionAdmin(admin.ModelAdmin):
    # ...
    list_display = ('question_text', 'pub_date', 'was_published_recently')
...

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

django_17

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

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

...
class Question(models.Model):
    question_text = models.CharField(max_length=200)
    pub_date = models.DateTimeField('date published')

    def was_published_recently(self):
        return self.pub_date >= timezone.now() - datetime.timedelta(days=1)

    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 снова, и добавьте фильтр list_display для отображения страницы изменений Question:

...
class QuestionAdmin(admin.ModelAdmin):
    fieldsets = [
        (None,               {'fields': ['question_text']}),
        ('Date information', {'fields': ['pub_date'], 'classes': ['collapse']}),
    ]
    inlines = [ChoiceInline]
    list_display = ('question_text', 'pub_date', 'was_published_recently')
    list_filter = ['pub_date']
...

Это добавит сайдбар Filter, который позволит выполнять сортировку по полю pub_date:

django_18

Тип фильтра будет зависеть от типа поля, которое вы добавили в фильтр. Так как pub_date – это объект DateTimeField Django знает, что подходящие фильтры тут – это “Any date“, “Today“, “Past 7 days“, “This month” и “This year“.

Давайте так же добавим возможно поиска по вопросам:

...
class QuestionAdmin(admin.ModelAdmin):
   #...
    search_fields = ['question_text']
...

Этим мы добавляем поле для поиска вверху страницу изменений:

django_19

Когда кто-то введёт текст для поиска – Django выполнит его поиск по полю question_text. Вы можете использовать любое количество полей, однако – так как тут используется SQL оператор LIKE – ограниченное количество полей для поиска сделает поиск более простым.

Также стоит обратить ваше внимание на то, что на странице изменений можно настроить нумерацию страниц. По умолчанию – будут отображаться 100 записей на одну страницу. С помощью change list pagination, search boxes, filters, date-hierarchies и column-header-ordering можно настроить вид админпанели так, как вы этого хотите.

Настройка внешнего вида панели управления

Если честно, надпись “Django administration” вверху панели управления выглядит не к месту.

Но – это очень просто изменить с помощью системы шаблонов Django. Панель управления Django управляется самой Django, а её внешний вид – это родная система шаблонов Django.

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

Создайте каталог templates в каталоге вашего проекта (том, который содержит файл manage.py). Шаблоны могут располагаться где угодно в файловой системе, лишь бы 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 на наличие файлов шаблонов.

Теперь – в каталоге templates создайте каталог admin, и скопируйте файл admin/base_site.html из каталога шаблонов Django – django/contrib/admin/templates в этот каталог (/usr/local/lib/python2.7/site-packages/Django-1.8.1-py2.7.egg/django/contrib/admin/templates/admin/, если вы устанавливали Django на CentOS по статье CentOS: обновление Python до 2.7 и установка Django 1.8):

$ mkdir templates/admin
$ cp /usr/local/lib/python2.7/site-packages/Django-1.8.1-py2.7.egg/django/contrib/admin/templates/admin/base_site.html templates/admin/

Где исходные файлы Djnago?

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

$ python -c "
import sys
sys.path = sys.path[1:]
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_20

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

Этот файл шаблона содержит много текста вида {% block branding %} и {{ title }}. Символы {% и {{ – это теги, часть языка системы шаблонов Django. Когда Django рендерит файл admin/base_site.html – этот язык шаблонов будет превращён в обычный HTML. Мы рассмотрим систему шаблонов далее (либо – вы можете с ней познакомиться на странице Django Book: основы системы шаблонов).

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

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

Внимательные читатели могут спросить – “Но если DIRS пуста по умолчанию – как Django находит свои шаблоны изначально?“. Ответ заключается в параметре APP_DIRS – так как он установлен в True, Django автоматически ищет каталог templates внутри каждого приложения, а  django.contrib.admin сам по себе является простым приложением Django.

Наше приложение голосования достаточно простое, и не требует особых настроек админпанели. Однако, если вам это потребуется – то лучше редактировать шаблон приложения, а не проекта.

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

Вы так же, возможно, захотите изменить внешний вид главной страницы админпанели.

По умолчанию – тут отображаются все приложения из списка INSTALLED_APPS, которые были зарегистрированы приложением admin, в алфавитном порядке.

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

Примечание: русификация панели управления описана в статье Django book: использование панели управления.