Недавний релиз Джанги 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/
Так же у объекта шаблонного контекста Context (и RequestContext) появился параметр current_app и при использовании тега {% url %} он будет браться для определения текущего инстанса приложения:
>>> tmpl = template.Template('{% url foo:index %}')
>>> tmpl.render(template.Context(current_app='foo1'))
/foo1/
Главное не сломайте себе мозг, поскольку при подключении урлов имя инстанса приложения указывается как параметр namespace, а при реверсинге как current_app.
Комментарии 11
Что-то я не заметил в этом большого смысла. А можно пример, где это может понадобиться?
Оставлен 04 Август 2009 в 03:00 ¶Ну я привел примеры админки и обобщенного приложения публикации контента. Что касается админки, то раньше она все эти манипуляции с урлами делала в виде некого хака. Сейчас же этот механизм узаконили и сделали доступным для всех.
Оставлен 04 Август 2009 в 12:49 ¶видать из-за этого гавна у меня reverse('admin_index') поотваливался
Оставлен 04 Август 2009 в 22:03 ¶Мне почему-то кажется что не это причина, но всё может быть.
Оставлен 04 Август 2009 в 22:16 ¶причина, глянул в доку, теперь таки admin:index
Оставлен 04 Август 2009 в 22:24 ¶А. Так это и есть тот самый тикет, который висел пару месяцев?
Оставлен 05 Август 2009 в 00:28 ¶Странная реакция в комментариях выше на эту фичу. Что, правда никто не понимает, почему стандартный механизм namespace'ов лучше зоопарка?
Оставлен 05 Август 2009 в 11:02 ¶Я думаю, что пока не у всех есть проекты где бы проблема конфликтов урлов вставала бы остро. Плюс, опять же не у всех, ещё выработалась практика вообще использовать реверсинг урлов - хардкодят по-старинке.
Оставлен 05 Август 2009 в 13:19 ¶а если include в include
Оставлен 07 Август 2009 в 00:38 ¶Если речь про разные неймспейсы в каждом из инклюдов, то они могут быть вложенными:
Оставлен 07 Август 2009 в 01:31 ¶а мне фича нравится, сразу юзать начал...
Оставлен 17 Декабрь 2009 в 23:08 ¶Оставьте комментарий