Александр Кошелев
Александр Кошелев Python-разработчик

У админки новые формы

Опять говорю “Ура!”. В предыдущий раз это это было в связи с апгрейдом ORM. На это раз кардинальным улучшениям подверглась ещё одна очень важная часть Django - автоматический CRUD, она же в официальной терминологии - админка. После достаточно продолжительного этапа разработки и тестирования NFA бранч влился в транк и подарил пользователям джанги кучу новых ощущений: от радости за сей факт, до тревоги по поводу необходимости переписывать имеющийся код. Но нас, любителей самых “свежих срезов”, это никогда не останавливало.:)

Многие уже успели изменить транку с NFA брачем и некоторое время погонять новую админку в своих проектах. Но не все такие смелые:)

Вообще это очень интересный процесс когда ты видишь по увеличившемуся числу changeset’ов перед релизом чего-то нового, что вот оно скоро свершится. Так было с Малкольмом, когда он допиливал рефакторинг ORM и произошло сейчас, благо спринт организовали. На этот раз главная звезда Брайен Роснер. Эти приятные хлопоты по полировке деталей, правки уже кажущихся не очень существенными сообщениями об ошибках, именования переменных и функций, и т.п. - как часть неотъемлемая часть.

Так что же мы получили? Во первых случился важнейший переворот в принципе описания админки. Если раньше её описание было частью определения модели, то теперь оно происходит отдельно. Что, наконец, дает возможность кастомизировать админку для моделей сторонних приложений без всяких хаков и редактирования чужого кода.

Помимо этого, возможности для кастомизации админки как таковой значительно расширились. Теперь более тонко можно настраивать её отображение и функционал.

И конечно же, сам факт появления адмника на новых формах в транке, приближает нас к долгожданному релизу версии 1.0 джанги. Который, если всё сложится как надо случиться уже в начале осени.

А теперь пройдемся по нововведениям и попытаемся сообразить, где нам это пригодится.

Настраиваем админку по новому

Для начала придумаем вот такую простую модель:

class Article( models.Model ):
   title = models.CharField( max_length = 250 )
   author = models.ForeignKey( User )
   date = models.DateTimeField( default = datetime.now )

   text = models.TextField()

Далее создадим класс описания админки для нашей модели. Кстати, нам рекомендуется, код админки хранить в файле admin.py, который автоматически импортируется в нужный момент.

from django.contrib import admin

class ArticleAdmin(admin.ModelAdmin):
   pass

admin.site.register(Article, ArticleAdmin)

В последней строке происходит регистрация данного описания админки и модели. Но это мы сделали дефолтную админку, теперь мы её будем кастомизировать.

class ArticleAdmin(admin.ModelAdmin):
   fieldsets = (
             (None, {
                 'fields': ('title', 'text', )
             }),
             ('Meta', {
                 'classes': ('collapse',),
                 'fields': ('author', 'date', )
             }),
         )

Как видно, изменилось название атрибута отвечающего за группировку полей при отображении формы редактирования. Раньше это были fields, теперь же это более логичные fieldsets. В остальном формат описания не изменился.

Ещё не плохо было бы избавиться от селект бокса, который отвечает а выбор автора. Благо теперь есть возможность превратить его в радио селект.

radio_fields = { "author" : admin.HORIZONTAL }

Аналогично можно сделать его и VERTICAL. Такую кастомизацию можно делать либо для ForeignKey полей, либо для тех у которых есть choices.

Конечно же сохранились и привычные list_display, search_fields, list_display_links, list_filter и т.д.

Теперь очень важное нововведение. Все мы помним, что edit_inline функциональность была реализована не очень хорошо в старых формах. И имела очень ограниченные возможности по настройке поведения. По сути можно было менять только кол-во отображаемых редактируемых элементов. Теперь же мы можем достаточно тонко настроить редактируемые инлайн объекты.

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

Формсеты

Формсет - это абстракция, позволяющая обрабатывать несколько однородных форм за раз (т.е. на одной странице). Поэтому они и родились в ходе работы над новой админкой, а точнее для редактируемых инлайн объектов.

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

class EntryForm( froms.Form ):
   name = forms.CharField()
   info = forms.TextField()

И для облегчения и убыстрения процесса мы захотели, чтобы можно было сразу несколько записей добавлять за раз. Тут на формсет и пригодится. Кстати, newforms стали теперь просто forms. Немного грустно, но так лучше:)

from django.forms.formsets import formset_factory
EntryFormset = formset_factory( EntryForm, extra = 3 )
formset = EntryFormset()

Вот таким не хитрым способом создается формсет из трех форм для добавления 3х записей. За количество клонов отвечает параметр extra.

Работать с ним достаточно просто. Для того чтобы пробежаться по всем формам набора надо:

for form in formset.forms:
   form.as_p()

Аналогично и в шаблоне.

Для обработки форм используется обобщенный механизм всего формсета, идентичный обычным формам:

if request.POST:
   formset = EntryFormset( request.POST )

   if formset.is_valid():
      #обрабатываем данные каждой из форм
else:
   formset = EntryFormset()

Также можно предоставлять начальные данные, добавлять поля и дополнительные валидаторы. Обо всем об этом можно прочитать в документации

Но и тут не обошлось без применения DRY принципа и формсет можно построить прям из модели примерно так:

from django.forms.models import modelformset_factory
EntryFormset = modelformset_factory( Entry )

И как обычно в документации всё подробно расписано.

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

Edit inline по новому

Вернемся к админке и настройке edit inline объектов. Путь для каждой нашей статьи будет присутствовать некоторые количество вспомогательных ссылок на какие-то полезные ресурсы. Модель для них будет такой:

class Link( models.Model ):
   article = models.ForeignKey( Article )

   name = models.CharField( max_length = 100 )
   url = models.URLField()

Ну и конечно не плохо чтобы сразу на странице добавления статьи мы могли бы и полезные ссылки к ней добавить. Тут то нам и пригодится ещё один новый мета-атрибут админки:

inlines = [ LinkInlineAdmin ]

Где LinkInlineAdmin это класс описатель для внедряемых форм добавления ссылок. Он описывается так:

class LinkInlineAdmin( InlineModelAdmin ):
   model = Link

Также как атрибут можно установить свой собственный formset или только форму - form, ну ещё кое-какие параметры.

Благодаря им, можно очень гибко настроить способ редактирования инлайн объектов.

Урлы для админки по новому

Теперь осталось правильно в urls.py указать на админку. Тут тоже всё по новому. Поскольку мы зарегистрировали мета-модель в глобально админке site, которая лежит в недрах contrib.admin, то маппинг должен выглядеть примерно так:

from django.conf.urls.defaults import *
from django.contrib import admin
 
urlpatterns = patterns('',
    ('^admin/(.*)', admin.site.root),
)

И тут мы получаем ещё один гибкий механизм, который нам позволяет иметь несколько админок. site это объект класса AdminSite, который мы можем создать сами и регистрировать “модельные” админки в нем. Соответственно и в urls.py ссылаться на них.

Вот собственно и всё.

Ещё, наконец, мы получили несколько generic views, который переведены на newforms. Это как приятное дополнение к обновленной адмике:)

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

Удачи нам и реализации самых смелых идей с админкой на новых формах!:)

comments powered by Disqus