Пространства имен

Недавний релиз Джанги 1.1 принес с собой новую фичу - пространства имен урлов. Цель они призваны достичь благую, но увы их механизм пока не очень прозрачен и понятен при первом приближении. Давайте разбираться.

Всё это родилось из идеи иметь несколько админок в одном проекте. И после рефакторинга админки под новые формы это стало возможным. Так же нужно было решить как разделять их урлы и главное как их реверсить по имени. Понятно, что в общем случае имена паттернов урлов разных админок будут пересекаться и однозначно преобразовать имя в урл невозможно. Тогда придумали каждому объекту SiteAdmin давать имя и это имя становилось частью названия паттерна урлов соответствующей админки. Ещё особенностью являлось то, что админка это объект и её урлы скрыты в атрибуте urls, что немного ломало классический способ инклюда урлов Джанги.

Что же сделали? Добавили разделение имен урлов. Причем разделенние на 2 уровня - уровень приложения и уровень инстанса приложения. Так что за приложения и что за инстансы?

Допустим у вас есть приложение foo, в котором присутствует какое-то количество урлов. Раньше хорошей практикой считалось урлы называть с префиксом имени приложения, например foo_index (или ещё каким-то уникальным идентификатором, что делала раньше админка (именем)). Теперь же. использую пространства имен, можно ограничится только index и указать foo как название нового неймспейса (или любое другое - тут полная свобода выбора разработчика). Указывать неймспейс нужно при инклюде этих урлов, например в корневом конфиге проекта:

(r'^foo/', include('foo.urls', app_name='foo', namespace='foo'))

или чуть более коротко:

(r'^foo/', include('foo.urls', namespace='foo'))

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

И теперь для реверсинга данных урлов достаточно указать название паттерна - foo:index. Для отделения названия неймспейса от названия урла используется двоеточие - :. Пространства имен также могут быть вложенными и отделяются друг от друга они тем же разделителем.

Задав параметр namespace, мы задали не просто название пространства имен, а по сути название данного инстанса приложения. А раз у приложения есть один инстанс, то может быть и другой. Вот эта очень полезная штука возвращающая нас к админке - одно и тоже приложение с один и тем же набором своих урлов может быть использовано в одном проекте несколько раз - это и есть инстансы. Помимо админок, например, очень удобно иметь обобщенное приложения публикации некого контента и использовать его как ленту новостей, как блог и гостевую книгу одновременно. Конечно поддержка такой многоголовости внутри приложения всё равно остается на разработчике, но уже на уровне урлов разруливания этих инстансов берет на себя Джанга (если конечно и многоголовость урлов вы не реализуете сами, что было единственным вариантом ранее).

(r'^foo/', include('foo.urls', namespace='foo')),
(r'^foo1/', include('foo.urls', app_name='foo', namespace='foo1')),
(r'^foo2/', include('foo.urls', app_name='foo', namespace='foo2'))

Тем самым я подключил 3 раза урлы одно и тоже приложение foo к разным базовым урлам, объединив их в одно приложение с логичным названием foo и для каждого присвоил свое пространство имен.

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

Как теперь эти урлы реверсить? У функции reverse появился дополнительный параметр current_app в котором задается название инстанса нужного приложения:

>>> from django.core.urlresolvers import reverse

>>> reverse('foo:index')
/foo/
>>> reverse('foo:index', current_app='foo1')
/foo1/
>>> reverse('foo:index', current_app='foo2')
/foo2/

Так же у объекта шаблонного контекста ContextRequestContext) появился параметр current_app и при использовании тега {% url %} он будет браться для определения текущего инстанса приложения:

>>> tmpl = template.Template('{% url foo:index %}')
>>> tmpl.render(template.Context(current_app='foo1'))
/foo1/

Главное не сломайте себе мозг, поскольку при подключении урлов имя инстанса приложения указывается как параметр namespace, а при реверсинге как current_app.

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

  1. sevenov написал:

    Что-то я не заметил в этом большого смысла. А можно пример, где это может понадобиться?

    Оставлен 04 Август 2009 в 03:00
  2. Александр Кошелев написал:

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

    Оставлен 04 Август 2009 в 12:49
  3. slav0nic написал:

    видать из-за этого гавна у меня reverse('admin_index') поотваливался

    Оставлен 04 Август 2009 в 22:03
  4. Александр Кошелев написал:

    видать из-за этого гавна у меня reverse('admin_index') поотваливался

    Мне почему-то кажется что не это причина, но всё может быть.

    Оставлен 04 Август 2009 в 22:16
  5. slav0nic написал:

    причина, глянул в доку, теперь таки admin:index

    Оставлен 04 Август 2009 в 22:24
  6. sevenov написал:

    А. Так это и есть тот самый тикет, который висел пару месяцев?

    Оставлен 05 Август 2009 в 00:28
  7. turbion_b5cc3a4c587bc31c2d1231 написал:

    Странная реакция в комментариях выше на эту фичу. Что, правда никто не понимает, почему стандартный механизм namespace'ов лучше зоопарка?

    Оставлен 05 Август 2009 в 11:02
  8. Александр Кошелев написал:

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

    Оставлен 05 Август 2009 в 13:19
  9. oduvan написал:

    а если include в include

    Оставлен 07 Август 2009 в 00:38
  10. Александр Кошелев написал:

    а если include в include

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

    bar:foo:index
    
    Оставлен 07 Август 2009 в 01:31
  11. http://ivanff.myopenid.org написал:

    а мне фича нравится, сразу юзать начал...

    Оставлен 17 Декабрь 2009 в 23:08