Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Django_-_podrobnoe_rukovodstvo

.pdf
Скачиваний:
306
Добавлен:
01.03.2016
Размер:
4.88 Mб
Скачать

130

Глава 6. Административный интерфейс Django

Приложение django.contrib.auth тоже включает файл admin.py, потомуто и присутствуют в таблице строки Users и Groups. Регистрируются в административном интерфейсе и другие приложения из пакета django. contrib, такие как django.contrib.redirects, а также многие сторонние приложения Django, которые есть в Интернете.

Во всех остальных отношениях административный интерфейс – обычное приложение Django со своими моделями, шаблонами,­ представлениями и образцами URL. Чтобы добавить его в свой проект, нужно завести образцы URL точно так же, как вы делаете это для собственных представлений. Заглянув в каталог django/contrib/admin в своей копии дистрибутива Django, вы сможете изучить шаблоны,­ представления и образцы URL административного интерфейса, но не пытайтесь что-то изменять прямо там, потому что есть вполне достаточно официальных точек подключения, позволяющих настроить работу административного интерфейса под себя. (Если вы все-таки решитесь модифицировать это приложение, имейте в виду, что при чтении метаданных о моделях оно делает довольно хитрые вещи, поэтому на то, чтобы разобраться в коде, может уйти много времени.)

Как сделать поле необязательным

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

Чтобы сделать поле email необязательным, откройте модель Book (напомним, что она находится в файле mysite/books/models.py) и добавьте в описание поля email параметр blank=True:

class Author(models.Model):

first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(blank=True)

Тем самым вы сообщили Django, что пустая строка является допустимым значением для адресов электронной почты. По умолчанию для всех полей blank=False, то есть пустые значения недопустимы.

Тут стоит отметить один интересный момент. До сих пор – если не считать метода __unicode__() – наши модели выступали в роли определений таблиц базы данных, по существу аналогами SQL-команды CREATE TABLE на языке Python. Но с добавлением параметра blank=True модель уже перестала быть только определением таблицы. Теперь она содержит более полные сведения о том, чем являются и что могут делать объекты Author. Мы знаем не только, что поле email представлено в базе данных

Как сделать поле необязательным

131

столбцом типа VARCHAR, но и что в некоторых контекстах, например в административном интерфейсе Django, оно необязательно.

Добавив параметр blank=True, перезагрузите форму редактирования информации об авторе (http://127.0.0.1:8000/admin/books/author/add/). Вы увидите, что метка поля – Email – уже не выделена жирным шрифтом. Это означает, что поле необязательное. Теперь можно добавить автора, не указывая адрес электронной почты, и сообщение «This field is required» (Это обязательное поле) не появится.

Как сделать необязательными поля даты и числовые поля

Существует типичная проблема, связанная с добавлением параметра blank=True для полей даты и числовых полей. Но чтобы разобраться

вней, потребуются дополнительные пояснения.

Вязыке SQL принят свой способ определения пустых значений – специальное значение NULL. Оно означает «неизвестно» или «отсутствует».

Вязыке SQL значение NULL отличается от пустой строки точно так же, как в языке Python объект None отличается от пустой строки “”. Следовательно, символьное поле (например, столбец типа VARCHAR) может содержать как NULL, так и пустую строку.

Это может приводить к нежелательной путанице: «Почему в этой записи данное поле содержит NULL, а в той – пустую строку? Между ними есть какая-то разница или данные просто введены неправильно?» Или такой вопрос: «Как получить все записи, в которых поле не заполнено, – искать NULL и пустые строки или только пустые строки?»

Чтобы разрешить эту неоднозначность, Django автоматически генерирует команды CREATE TABLE (см. главу 5) с явной спецификацией NOT NULL в определении каждого столбца. Вот, например, как выглядит сгенерированная команда для модели Author из главы 5:

CREATE TABLE “books_author” (

“id” serial NOT NULL PRIMARY KEY, “first_name” varchar(30) NOT NULL, “last_name” varchar(40) NOT NULL, “email” varchar(75) NOT NULL

)

;

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

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

132

Глава 6. Административный интерфейс Django

всего, получите ошибку базы данных, хотя это и зависит от конкретной СУБД. (PostgreSQL строго контролирует типы данных и в этом случае возбудит исключение; MySQL может принять пустую строку или отвергнуть в зависимости от версии, времени суток и фазы Луны.) В таком случае NULL – единственный способ задать пустое значение. В моделях Django можно сказать, что значения NULL допустимы, добавив в описание поля параметр null=True.

Короче говоря, если вы хотите разрешить пустые значения в числовых полях (например, IntegerField, DecimalField, FloatField) или полях, содержащих дату (например, DateField, TimeField, DateTimeField), то включайте оба параметра null=True и blank=True.

В качестве примера изменим модель Book так, чтобы пустая дата публикации publication_date была допустима. Вот как выглядит модифицированный код:

class Book(models.Model):

title = models.CharField(max_length=100) authors = models.ManyToManyField(Author) publisher = models.ForeignKey(Publisher)

publication_date = models.DateField(blank=True, null=True)

С добавлением null=True связано больше сложностей, чем с добавлением blank=True, поскольку параметр null=True изменяет семантику базы данных, то есть в команде CREATE TABLE требуется удалить спецификацию NOT NULL из описания столбца publication_date. Чтобы довести модификацию до конца, необходимо обновить базу данных.

По ряду причин Django не пытается автоматизировать изменение схемы базы данных, поэтому вы должны сами выполнить соответствующую команду ALTER TABLE для внесения такого изменения в модель. Напомним, что команда manage.py dbshell позволяет запустить клиент для используемой СУБД. Вот как можно удалить спецификацию NOT NULL в нашем конкретном случае:

ALTER TABLE books_book ALTER COLUMN publication_date DROP NOT NULL;

(Отметим, что этот синтаксис специфичен для СУБД PostgreSQL.) По­ дробнее изменение схемы базы данных рассматривается в главе 10.

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

Изменение меток полей

Метки полей в формах редактирования в административном интерфейсе генерируются исходя из имени поля в модели. Алгоритм прост: Django просто заменяет знаки подчеркивания пробелами и переводит

Настроечные классы ModelAdmin

133

первый символ в верхний регистр. Например, для поля publication_date в модели Book получается метка Publication Date.

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

Например, вот как можно поменять метку поля Author.email на e-mail с черточкой:

class Author(models.Model):

first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40)

email = models.EmailField(blank=True, verbose_name=’e-mail’)

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

Отметим, что не следует делать первую букву в значении параметра verbose_name заглавной, если она не должна быть заглавной всегда (как, например, в «USA state»). Django автоматически переводит ее в верхний регистр, когда это требуется, и использует значение, заданное в verbose_name, в тех местах, где заглавные буквы не нужны.

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

class Author(models.Model):

first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40) email = models.EmailField(‘e-mail’, blank=True)

Однако такое решение не годится для полей вида ManyToManyField или ForeignKey, потому что в их описаниях первый аргумент обязательно должен быть классом модели. В таких случаях приходится явно указывать имя параметра verbose_name.

Настроечные классы ModelAdmin

Изменения, о которых мы говорили до сих пор, – blank=True, null=True и verbose_name – производились на уровне модели, а не административного интерфейса. Иначе говоря, эти параметры по сути своей являются частью модели, а административный интерфейс их просто использует; ничего относящегося исключительно к администрированию в них нет.

Но Django также предлагает много способов изменить порядок работы административного интерфейса для конкретной модели. Такие изменения производятся в классах ModelAdmin, содержащих конфигурационные параметры отдельной модели в отдельном экземпляре административного интерфейса.

134

Глава 6. Административный интерфейс Django

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

Приступая к настройке административного интерфейса, начнем с того, что определим поля, отображаемые в списке для изменения модели Author. По умолчанию в этом списке отображается результат работы метода __unicode__() для каждого объекта. В главе 5 мы определили метод __unicode__()для объектов Author так, чтобы выводились имя и фамилия:

class Author(models.Model):

first_name = models.CharField(max_length=30) last_name = models.CharField(max_length=40)

email = models.EmailField(blank=True, verbose_name=’e-mail’)

def __unicode__(self):

return u’%s %s’ % (self.first_name, self.last_name)

Поэтому в списке объектов Author отображаются имена и фамилии авторов, как показано на рис. 6.7.

Рис. 6.7. Страница со списком авторов

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

Настроечные классы ModelAdmin

135

Для этого мы определим класс ModelAdmin для модели Author. Он является ключом к настройке административного интерфейса, а одна из самых простых его функций – возможность добавлять поля в списки для изменения. Модифицируйте файл admin.py следующим образом:

from django.contrib import admin

from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):

list_display = (‘first_name’, ‘last_name’, ‘email’)

admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book)

Опишем, что же мы сделали:

•• Мы создали класс AuthorAdmin. Он является подклассом django. contrib.admin.ModelAdmin и содержит дополнительную информацию, описывающую порядок представления конкретной модели в административном интерфейсе. Пока мы задали лишь один параметр list_display, указав в нем кортеж, содержащий имена полей, отображаемых в списке для изменения. Разумеется, это должны быть поля, присутствующие в модели.

•• Мы изменили обращение к функции admin.site.register(), добавив параметр AuthorAdmin после Author. Эту строчку можно прочитать так: «Зарегистрировать модель Author с параметрами AuthorAdmin».

Функция admin.site.register() принимает подкласс ModelAdmin в качестве второго необязательного аргумента. Если второй аргумент не задан (как в случае моделей Publisher и Book), то используются параметры, принимаемые по умолчанию.

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

Теперь добавим простую панель поиска. Добавьте в класс AuthorAdmin

поле search_fields:

class AuthorAdmin(admin.ModelAdmin):

list_display = (‘first_name’, ‘last_name’, ‘email’) search_fields = (‘first_name’, ‘last_name’)

Перезагрузив страницу в броузере, вы увидите сверху панель поиска (рис. 6.9). Только что мы потребовали включить в страницу списка для изменения панель, позволяющую выполнять поиск по содержимому полей first_name и last_name. Как и ожидает пользователь, при поиске не учитывается регистр букв и просматриваются оба поля, то есть поиск по строке «bar» найдет авторов с именем Barney и автора с фамилией Hobarson.

136

Глава 6. Административный интерфейс Django

 

 

 

 

 

 

Рис. 6.8. Страница со списком авторов после добавления параметра list_display

Рис. 6.9. Страница со списком авторов после добавления параметра search_fields

Настроечные классы ModelAdmin

137

Далее добавим в модель Book несколько фильтров дат:

from django.contrib import admin

from mysite.books.models import Publisher, Author, Book

class AuthorAdmin(admin.ModelAdmin):

list_display = (‘first_name’, ‘last_name’, ‘email’) search_fields = (‘first_name’, ‘last_name’)

class BookAdmin(admin.ModelAdmin):

list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,)

admin.site.register(Publisher) admin.site.register(Author, AuthorAdmin) admin.site.register(Book, BookAdmin)

Поскольку параметры для двух моделей различны, мы создали отдельный подкласс класса ModelAdmin – BookAdmin. Сначала мы определили параметр list_display, просто чтобы улучшить внешний вид списка для изменения, а затем с помощью параметра list_filter задали кортеж полей, которые должны быть включены в состав фильтров справа от списка. Для полей типа даты Django автоматически предлагает фильтры «Today» (Сегодня), «Past 7 days» (За последние 7 дней), «This month» (В этом месяце) и «This year» (В этом году). Разработчики Django считают, что эти фильтры полезны в большинстве случаев. На рис. 6.10 показано, как все это выглядит.

Параметр list_filter работает и для полей других типов, а не только DateField. (Попробуйте, например, применить его к полям типа BooleanField и ForeignKey.) Фильтры отображаются только в том случае, когда имеются по меньшей мере два разных значения.

Есть еще один способ определить фильтры по дате – воспользоваться параметром административного интерфейса date_hierarchy:

class BookAdmin(admin.ModelAdmin):

list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,)

date_hierarchy = ‘publication_date’

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

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

Наконец, изменим подразумеваемую по умолчанию сортировку, чтобы книги на странице списка для изменения сортировались в порядке убывания даты публикации. По умолчанию объекты в этом списке упорядочены в соответствии с параметром модели ordering, заданным

138

Глава 6. Административный интерфейс Django

 

 

 

 

 

 

Рис. 6.10. Страница со списком книг после добавления параметра list_filter

Рис. 6.11. Страница со списком книг после добавления параметра date_hierarchy

Настроечные классы ModelAdmin

139

в классе Meta (мы рассказывали о нем в главе 5), но если этот параметр не задан, то порядок сортировки не определен.

class BookAdmin(admin.ModelAdmin):

list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,)

date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,)

Параметр ordering в административном интерфейсе работает так же, как одноименный параметр в классе модели Meta, с тем отличием, что

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

впорядке убывания.

Перезагрузите список книг, чтобы увидеть, как это работает. Обратите внимание, что теперь в заголовке столбца Publication Date появилась стрелочка, показывающая, каким способом записи отсортированы (рис. 6.12).

Рис. 6.12. Страница со списком книг после добавления параметра ordering

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]