Настроечные классы ModelAdmin
Изменения, о которых мы говорили до сих пор, - blank=True, null=True и verbose_name - производились на уровне модели, а не административного интерфейса. Иначе говоря, эти параметры по сути своей являются частью модели, а административный интерфейс их просто использует; ничего относящегося исключительно к администрированию в них нет.
Но Django также предлагает много способов изменить порядок работы административного интерфейса для конкретной модели. Такие изменения производятся в классах ModelAdmin, содержащих конфигурационные параметры отдельной модели в отдельном экземпляре административного интерфейса.
Настройка списков для изменения
Приступая к настройке административного интерфейса, начнем с того, что определим поля, отображаемые в списке для изменения модели Author. По умолчанию в этом списке отображается результат работы метода Unicode () для каждого объекта. В главе 5 мы определили метод
____ Unicode__ ()для объектов Author так, чтобы выводились имя и фамилия:
class Author(models.Model):
first_nane = 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. Страница со списком авторов
Мы можем улучшить это подразумеваемое по умолчанию поведение, добавив еще несколько полей в список для изменения. Например, хорошо было бы видеть в списке адрес электронной почты автора и иметь возможность сортировки по имени и по фамилии.
Для этого мы определим класс Mod el Admin для модели Author. Он является ключом к настройке административного интерфейса, а одна из самых простых его функций - возможность добавлять поля в списки для изменения. Модифицируйте файл admin.ру следующим образом:
from django.contrib import admin
from mysite.books.models import Publisher, Author, Book
class AuthorAdmin(admin.ModelAdmin):
list_display = (‘f1rst_name’, ‘last_name’, ’email’)
admin.site.register(Pub!isher)
admin.site.register(Author, AuthorAdmin)
admin.site.register(Book)
Опишем, что же мы сделали:
• Мы создали класс AuthorAdmin. Он является подклассом django. contrib.admin.ModelAdmin и содержит дополнительную информацию, описывающую порядок представления конкретной модели в административном интерфейсе. Пока мы задали лишь один параметр list_display, указав в нем кортеж, содержащий имена полей, отображаемых в списке для изменения. Разумеется, это должны быть поля, присутствующие в модели.
• Мы изменили обращение к функции admin.site.registerQ, добавив параметр 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.
Puc. 6.8. Страница со списком авторов после добавления параметра list_display
Puc. 6.9. Страница со списком авторов после добавления параметра search_fields
Далее добавим в модель 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’) 1ist_fiIter = (‘publication_date’,)
admin.site.register(Publisher)
admin.site.register(Author, AuthorAdmin)
admin.site. register(Book, BookAdmin)
Поскольку параметры для двух моделей различны, мы создали отдельный подкласс класса ModelAdmin - BookAdmin. Сначала мы определили параметр list_display, просто чтобы улучшить внешний вид списка для изменения, а затем с помощью параметра list_f ilter задали кортеж полей, которые должны быть включены в состав фильтров справа от списка. Для полей типа даты 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, заданным
Рис. 6.10. Страница со списком книг после добавления параметра list_filter
Рис. 6.11. Страница со списком книг после добавления параметра date_hierarchy
в классе Meta (мы рассказывали о нем в главе 5), но если этот параметр не задан, то порядок сортировки не определен.
class BookAdnin(adnin.ModelAdmin):
list_display = (‘title’, ‘publisher’, ‘publication_date’) list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date" ordering = (‘-publication_date’,)
Параметр ordering в административном интерфейсе работает так же, как одноименный параметр в классе модели Meta, с тем отличием, что в действительности используется только первое имя поля в списке. Вам достаточно указать в качестве значения список или кортеж имен полей и добавить перед именем поля знак минус, если требуется сортировать в порядке убывания.
Перезагрузите список книг, чтобы увидеть, как это работает. Обратите внимание, что теперь в заголовке столбца Publication Date появилась стрелочка, показывающая, каким способом записи отсортированы (рис. 6.12).
Puc. 6.12. Страница со списком книг после добавления параметра ordering
Итак, мы рассмотрели основные параметры отображения списка для изменения. С их помощью можно организовать весьма мощный готовый для эксплуатации интерфейс редактирования, написав всего несколько строчек кода.
Настройка форм редактирования
Формы редактирования, как и списки для изменения, можно настраивать.
Для начала изменим порядок следования полей ввода. По умолчанию поля ввода в форме следуют в том порядке, в котором определены в модели. Но это можно изменить с помощью параметра fields в подклассе класса ModelAdmin:
class BookAdmin(admin.ModelAdmin):
list_display =(‘title’, * publisher’, ‘publication_date’) 1ist_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’,)
fields = (‘title’, ‘authors’, ‘publisher’, ‘publication_date’)
Теперь в форме редактирования книги поля будут расположены в указанном порядке. Нам кажется, что более естественно сначала ввести название книги, а потом имена авторов. Разумеется, порядок следования полей зависит от принятой в конкретной организации технологической процедуры ввода данных. Нет двух одинаковых форм.
У параметра fields есть еще одна полезная особенность: он позволяет исключить некоторые поля из формы редактирования. Для этого достаточно не перечислять их в списке. Этой возможностью можно воспользоваться, если вы не доверяете администраторам изменять некоторые данные или если какие-то поля изменяются внешней автоматической процедурой. Например, мы могли бы запретить редактирование поля publication_date:
class BookAdmin(admin.ModelAdmin):
list_display = (‘title’, ‘publisher’, ‘publication_date’)
list_filter = (‘publication_date’,)
date_hierarchy = ‘publication_date’
ordering = (‘-publication_date’,)
fields = (‘title’, ‘authors’, ‘publisher’)
Теперь форма редактирования не позволит задать дату публикации. Например, это может пригодиться, если вы издатель и не хотите, чтобы авторы могли выражать несогласие с датой публикации (конечно, ситуация чисто гипотетическая).
Когда пользователь отправит такую неполную форму для добавления новой книги, Django просто установит поле publication_date в None, поэтому не забудьте добавить в определение такого поля параметр null=True.
Еще одна часто применяемая настройка формы редактирования имеет отношение к полям типа многие-ко-многим. На примере формы редактирования книг мы видели, что в административном интерфейсе поля типа ManyToManyField представлены в виде списка с множественным выбором. Из элементов ввода данных, имеющихся в HTML, это наиболее подходящий, но работать с такими списками трудновато. Чтобы выбрать несколько элементов, нужно удерживать клавишу Control (или Command на платформе Мае). Административный интерфейс услужливо выводит соответствующую подсказку, но все равно для списка, содержащего несколько сотен элементов, это неудобно.
‘publication_date’)
Для решения этой проблемы в административном интерфейсе можно использовать параметр filter_horizontal. Добавим его в класс BookAdmin и посмотрим, что произойдет.
class BookAdmin(admin.ModelAdmin):
list_display = (‘title’, ‘publisher’ list_filter = (‘publication_date’,) date_hierarchy = ‘publication_date’ ordering = (‘-publication_date’, ) filter_horizontal = (‘authors’,)
(Если вы выполняете предлагаемые упражнения, то обратите внимание, что заодно мы удалили параметр fields, чтобы в форме снова присутствовали все поля.)
Перезагрузив форму редактирования книг, вы увидите, что теперь в разделе Authors (Авторы) появился симпатичный реализованный на JavaScript интерфейс фильтра, позволяющий отыскивать и перемещать интересующих вас авторов из списка Available Authors (Имеющиеся авторы) в список Chosen Authors (Выбранные авторы) или наоборот.
Puc. 6.13. Форма редактирования книги после добавления параметра filter_horizontal
Мы настоятельно рекомендуем использовать параметр f ilter_horizontal в случаях, когда количество значений поля типа ManyToManyField больше десяти. Это гораздо проще, чем список с множественным выбором. Кроме того, отметим, что filter__horizontal можно применять и к нескольким полям - достаточно перечислить их имена в кортеже.
Классы ModelAdmin поддерживают также параметр filter_vertical. Он работает так же, как filter_horizontal, только списки расположены не рядом, а один под другим. Каким пользоваться, дело вкуса.
Параметры filter_horizontal и filter_vertical применимы только к полям типа ManyToManyField и не могут использоваться для полей типа ForeignKey. По умолчанию для полей типа ForeignKey в административном интерфейсе используются раскрывающиеся списки <select>, но иногда, как и в случае ManyToManyField, желательно избежать накладных расходов, обусловленных загрузкой сразу всех связанных объектов в список. Например, если в нашей базе данных со временем окажется несколько тысяч издательств, то форма добавления книги Add Book будет загружаться довольно долго, так как названия всех издательств придется скопировать в список <select>.
Дело можно поправить с помощью параметра raw_id_fields. Если присвоить ему в качестве значения кортеж имен полей типа ForeignKey, то такие поля будут представлены в административном интерфейсе простым полем ввода (<input type="text">), а не списком <select> (рис. 6.14).
class BookAdmin(admin.ModelAdmin):
list_display = (‘title’, ‘publisher’, ‘publication_date’)
list_filter = (‘publication_date’,)
date_hierarchy = ‘publication_date’
ordering = (‘-publication_date’,)
filter_horizontal = (‘authors’,)
raw_id_fields = (‘publisher’,)
Что вводится в это поле? Идентификатор издательства в базе данных. Поскольку люди обычно не помнят эти идентификаторы, то справа от поля находится значок лупы - при щелчке на нем появится всплывающее окно, где можно будет выбрать издательство.
Пользователи, группы и разрешения
Поскольку вы вошли в систему как суперпользователь, то имеете право создавать, редактировать и удалять любые объекты. Естественно, в зависимости от обстоятельств могут понадобиться и другие наборы разрешений - нельзя же всем быть суперпользователями. В административном интерфейсе Django реализована система, позволяющая разрешать пользователям доступ только к тем частям интерфейса, которые им необходимы.
Рис. 6.14. Форма редактирования книги после добавления параметра raw_id_fields
Учетные записи пользователей спроектированы так, чтобы их можно было использовать и вне административного интерфейса, но сейчас мы будем считать, что они служат только для входа в этот интерфейс. В главе 14 мы расскажем о том, как интегрировать учетные записи с прочими частями сайта.
Административный интерфейс позволяет редактировать пользователей и разрешения точно так же, как любые другие объекты. Мы уже видели, что в интерфейсе имеются разделы User (Пользователь) и Group (Группа). У пользователя, как и следовало ожидать, есть имя, пароль, адрес электронной почты и реальное имя, а также ряд полей, показывающих, что ему разрешено делать в административном интерфейсе. Во-первых, это три булевских флажка:
• Флажок «active» показывает, активен ли пользователь. Если он сброшен, то система не пустит пользователя даже с правильным паролем.
• Флажок «staff» управляет тем, разрешено ли пользователю заходить в административный интерфейс (то есть считается ли он «сотрудником» организации). Поскольку эта же система может применяться
для управления доступом к открытым (не административным) частям сайта (см. главу 14), то этот флажок позволяет отличить обычных пользователей от администраторов.
• Флажок «superuser» предоставляет полный доступ к созданию, изменению и добавлению любых объектов в административном интерфейсе. Если для некоторого пользователя этот флажок отмечен, то все обычные разрешения (или их отсутствие) для него игнорируются.
«Обычным» администраторам, то есть сотрудникам, не являющимся суперпользователями, предоставляется доступ в соответствии с назначенными им разрешениями. Для каждого объекта, который можно редактировать в административном интерфейсе (книги, авторы, издательства), определено три разрешения: создать, редактировать и удалить. Назначение этих разрешений пользователю дает ему соответствующий уровень доступа.
Только что созданный пользователь не имеет никаких разрешений, вы должны назначить их явно. Например, можно разрешить пользователю добавлять и изменять, но не удалять издательства. Отметим, что разрешения определяются на уровне модели, а не объекта, то есть можно сказать, что «Джон может изменять любую книгу», но нельзя сказать, что «Джон может изменять любую книгу, опубликованную издательством Apress». Разрешения на уровне объекта - более сложная тема, которая выходит за рамки данной книги (но рассмотрена в документации по Django).
Примечание —————————————————————————-
Доступ к редактированию пользователей и разрешений также управляется этой же системой разрешений. Если вы разрешите кому-нибудь редактировать пользователей, то он сможет изменить и свои собственные разрешения, а это вряд ли входило в ваши намерения! Разрешение редактировать других пользователей по существу превращает обычного пользователя в суперпользователя.
Пользователей можно также объединять в группы. Группа - это просто набор разрешений, действующих для всех ее членов. Группы полезны, когда нужно назначить одинаковые разрешения сразу нескольким пользователям.
Источник: Головатый А., Каплан-Мосс Дж. Django. Подробное руководство, 2-е издание. - Пер. с англ. - СПб.: Символ- Плюс, 2010. - 560 е., ил.