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

Опять говорю "Ура!". В предыдущий раз это это было в связи с апгрейдом 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. Это как приятное дополнение к обновленной адмике:)

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

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

Комментарии 14

  1. Kirill Morozov написал:

    Огромное спасибо за обзор! будем изучать

    Оставлен 19 Июль 2008 в 08:42
  2. syncsync написал:

    Интересно а alias newforms останется в грядущих апдейтах? Много проектов поэтому как то боязно апдейтить транк :-) P.S pycaptcha - страшная :-)

    Оставлен 19 Июль 2008 в 17:51
  3. slav0nic написал:

    наверно ещё admin.autodiscover() забыл в urls.py ;)

    Оставлен 20 Июль 2008 в 21:21
  4. Dyadya Zed написал:

    Спасибо за статью!

    Было бы намного нагляднее показать скриншоты админки например для Edit inline, опций admin.HORIZONTAL и т.д. В принципе представить можно, но "одна картинка стоит тысячи слов"...

    Оставлен 21 Июль 2008 в 13:06
  5. Александр Кошелев написал:

    наверно ещё admin.autodiscover() забыл в urls.py ;)

    Ага. Его в дефолтный шаблон проекта уже включили.

    Оставлен 21 Июль 2008 в 15:26
  6. Александр Кошелев написал:

    В принципе представить можно, но "одна картинка стоит тысячи слов"...

    Так практически также как и раньше выглядит, только чуть-чуть добавили функционала в виде "чекбокса удаления".

    Оставлен 21 Июль 2008 в 15:27
  7. Александр Кошелев написал:

    Интересно а alias newforms останется в грядущих апдейтах?

    Нет.

    Много проектов поэтому как то боязно апдейтить транк :-

    Ну на самом деле и контекстной заменой можно быстро решить.

    P.S pycaptcha - страшная :-)

    Абсолютно согласен. Скорое её убью:)

    Оставлен 21 Июль 2008 в 15:29
  8. Vitaliy написал:

    Интересно а alias newforms останется в грядущих апдейтах? Много проектов поэтому как то боязно апдейтить транк

    Меня очень раздражало это new/old - я вчера сел и во всех проектах заменил - в Eclipse довольно все быстро это делается и никаких боков не наблюдается

    ЗЫ: 2 Александр - что-то предпросмотр комментария не работает (пустое облачко отображается)

    Оставлен 22 Июль 2008 в 11:50
  9. Fox написал:

    Обновил версию django. Первый раз почуствовал прелести не релизоности django.

    Во первых

    Это перестало работать (r'^admin/', include('django.contrib.admin.urls')), конечно теперь есть более красивое вроде бы Но не более логичное ('^myadmin/(.*)', admin.site.root),

    Все бы ничего. (Особенно inline)

    Только исчезло управление юзерами и их правами. Как вернуть???

    P.S.В доке не нашел.

    Оставлен 23 Июль 2008 в 18:45
  10. Александр Кошелев написал:

    Fox, читайте документацию по новой админке. Там всё описано.

    Если используете последний срез джанги, то не забывайте перед svn up проверять страницу несовместимых изменений. Тогда неожиданностей не будет.

    Оставлен 23 Июль 2008 в 19:22
  11. Roman написал:

    date = models.DateTimeField( default = datetime.now )

    но perhaps, it's right :-))

    date = models.DateTimeField( default = datetime.datetime.now() )

    ошибочка понимаешь в коде будет.

    admin.site.register(Article, ArticleAdminn)

    it is too mistake because double nn

    Спасибо

    Оставлен 14 Август 2008 в 00:12
  12. Roman написал:

    Здравствуйте!!!

    Цитата из поста

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

    А где это написано что admin.py использовать надо и как это автоматически импортируется то есть что не нужно прописывать его нигде ?

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

    Оставлен 14 Август 2008 в 00:21
  13. Александр Кошелев написал:

    ошибочка понимаешь в коде будет.

    Почему?

    double nn

    опечатка

    Оставлен 14 Август 2008 в 11:59
  14. Александр Кошелев написал:

    А где это написано что admin.py использовать надо и как это автоматически импортируется то есть что не нужно прописывать его нигде ?

    Так вот тут. В стандартно-сгенерированном urls.py будет admin.autodiscover()

    Оставлен 14 Август 2008 в 12:05