Менеджер URL-ов

Чистая, элегантная схема URL-ов – это важная часть качественного приложения. Django позволяет проектировать URL-адреса как вы пожелаете, без ограничений “фреймверка”.

В URL-ах не нужны ни .php, ни .cgi, ни всякая ерунда вроде 0,2097,1-1-1928,00.

Читайте Cool URIs don’t change, создателя World Wide Web, Тима Бернерса-Ли, чтобы узнать почему URL-ы должны быть красивыми и практичными.

Обзор

Для определения URL-ов приложения, создайте модуль Python, неофициально названный URLconf (конфигурация URL-ов). Этот модуль содержит код Python, который отображает URL-шаблоны (регулярные выражения) и связанные функции Python (ваши представления).

Эта конфигурация может быть короткой или длинной настолько, насколько это нужно. Она может ссылаться на другие конфигурации. И, так как это код Python, может создаваться динамически.

Django также предоставляет метод для перевода URL на текущий язык. Обратитесь к документации на интернационализацию для подробностей.

Как Django обрабатывает запрос

При запросе к странице вашего Django-сайта, используется такой алгоритм для определения какой код выполнить:

  1. Django определяет какой корневой модуль URLconf использовать. Обычно, это значение настройки ROOT_URLCONF, но, если объект запроса HttpRequest содержит атрибут urlconf (установленный request middleware), его значение будет использоваться вместо ROOT_URLCONF.

  2. Django загружает модуль конфигурации URL и ищет переменную urlpatterns. Это должен быть список Python, в формате возвращаемом функцией django.conf.urls.patterns().

  3. Django перебирает каждый URL-шаблон по порядку, и останавливается при первом совпадении с запрошенным URL-ом.

  4. Если одно из регулярных выражений соответствует URL-у, Django импортирует и вызывает соответствующее представление, которое является просто функцией Python(или представление-класс). При вызове первым аргументом передается HttpRequest а также все значения найденные регулярным выражением.

  5. Если ни одно регулярное выражение не соответствует, или возникла ошибка на любом из этапов, Django вызывает соответствующий обработчик ошибок. Смотрите `Error handling`_ ниже.

Например

Вот пример простого URLconf:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^articles/2003/$', 'news.views.special_case_2003'),
    url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
    url(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

Заметим:

  • Для получения совпадающего значения из URL, просто добавьте скобки вокруг него.

  • Не нужно добавлять косую черту в начале, потому что каждый URL содержит его. Например, используйте ^articles, вместо ^/articles.

  • Символ 'r' перед каждым регулярным выражением не обязателен, но рекомендуется. Он указывает Python что строка “сырая(raw)” и ничего в строке не должно быть экранировано. Смотрите Dive Into Python’s explanation.

Примеры запросов:

  • Запрос к``/articles/2005/03/`` будет обработан третьим элементом списка. Django вызовет функцию news.views.month_archive(request, '2005', '03').

  • /articles/2005/3/ не соответствует ни одному URL-шаблону, потому что третья запись требует две цифры в номере месяца.

  • /articles/2003/ соответствует первому выражению, не второму, потому что шаблоны проверяются по порядку. Не стесняйтесь использовать порядок для обработки различных ситуаций, таких как эта.

  • /articles/2003 не соответствует ни одному регулярному выражению, потому что каждое ожидает, что URL оканчивается на косую черту.

  • /articles/2003/03/03/ соответствует последнему выражению. Django вызовет функцию news.views.article_detail(request, '2003', '03', '03').

Именованные группы

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

Для регулярных выражений в Python синтаксис для именованных совпадений выглядит таким образом (?P<name>pattern), где name это название группы, а pattern – шаблон.

Вот пример конфигурации URL, переписанный с использованием именованных групп:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^articles/2003/$', 'news.views.special_case_2003'),
    url(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),
    url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/$', 'news.views.month_archive'),
    url(r'^articles/(?P<year>\d{4})/(?P<month>\d{2})/(?P<day>\d{2})/$', 'news.views.article_detail'),
)

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

  • Запрос к /articles/2005/03/ вызовет функцию news.views.month_archive(request, year='2005', month='03'), вместо news.views.month_archive(request, '2005', '03').

  • Запрос к /articles/2003/03/03/ вызовет news.views.article_detail(request, year='2003', month='03', day='03').

На практике это означает, что ваша конфигурация URL более понятна и меньше зависит от ошибки в порядке аргументов, также вы можете изменять порядок аргументов в представлении. Конечно, эти преимущества достигаются за счет краткости, некоторые разработчики считают именованные группы уродливыми и слишком многословными.

Алгоритм соответствия/группировки

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

  1. Если существует именованный аргумент, он будет использован вместо позиционного аргумента.

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

В любом случае дополнительные именованные аргументы будут переданы как именованные. Смотрите `Passing extra options to view functions`_ ниже.

Что использует URLconf при поиске нужного шаблона URL

URLconf использует запрашиваемый URL как обычную строку Python. Он не учитывает параметры GET, POST и имя домена.

Например, при запросе к http://www.example.com/myapp/, URLconf возьмет myapp/.

При запросе к http://www.example.com/myapp/?page=3myapp/.

URLconf не учитывает тип запроса. Другими словами, все типы запросов – POST, GET, HEAD, и др. – будут обработаны одним представлением при одинаковом URL.

Особенности нахождении аргументов в URL

Каждый найденный аргумент передается в представление как строка, независимо от того, какое “совпадение” определено в регулярном выражении. Например, URLconf содержит такую строку:

url(r'^articles/(?P<year>\d{4})/$', 'news.views.year_archive'),

...аргумент year для news.views.year_archive() будет строкой, несмотря на \d{4}.

Принято указывать значения по-умолчанию для аргументов представления. Пример URLconf и представления:

# URLconf
from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^blog/$', 'blog.views.page'),
    url(r'^blog/page(?P<num>\d+)/$', 'blog.views.page'),
)

# View (in blog/views.py)
def page(request, num="1"):
    # Output the appropriate page of blog entries, according to num.
    ...

В примере выше, оба URL-шаблона указывают на одно представление – blog.views.page – но первый шаблон не принимает аргументы в URL. Если первый шаблон будет выбран, функция page() будет использовать значение по-умолчанию аргумента num равное "1". Если будет выбран другой шаблон, page() будет использовать значение num из URL, которое найдет регулярное выражение.

Производительность

Каждое регулярное выражение в urlpatterns будет скомпилировано при первом использовании. Это делает систему невероятно быстрой.

Синтаксис переменной urlpatterns

urlpatterns должен быть списком Python, в формате, возвращаемом функцией django.conf.urls.patterns(). Всегда используйте patterns() для определения переменной urlpatterns.

Обработчики ошибок

Если Django не может найти подходящий шаблон URL, или было вызвано исключение в процессе обработки запроса, Django вызовет соответствующее представление обрабатывающее ошибку.

Эти представления определены в четырёх переменных. Их значения по-умолчанию должны подойти для большинства проектов, но вы можете их поменять при необходимости.

Подробности в разделе о переопределении обработчика ошибок.

Эти значения должны быть определены в главном URLconf.

Значение это функции, или полный путь для импорта, которая будет вызвана, если не был найден подходящий URL-шаблон.

Есть следующие переменные:

Префикс представления

Вы можете указать общий префикс при вызове patterns(), чтобы сократить дублирование кода.

Вот пример URLconf из обзора Django:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
    url(r'^articles/(\d{4})/(\d{2})/$', 'news.views.month_archive'),
    url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'news.views.article_detail'),
)

В этом пример, каждое представление содержит общий префикс – 'news.views'. Вместо того, чтобы писать его для каждой записи urlpatterns, вы можете указать его первым аргументом функции patterns().

Теперь можно переписать пример выше:

from django.conf.urls import patterns, url

urlpatterns = patterns('news.views',
    url(r'^articles/(\d{4})/$', 'year_archive'),
    url(r'^articles/(\d{4})/(\d{2})/$', 'month_archive'),
    url(r'^articles/(\d{4})/(\d{2})/(\d+)/$', 'article_detail'),
)

Заметим что в конце префикса отсутствует точка ("."). Django самостоятельно добавит ее.

Несколько префиксов представления

На практике, скорее всего представления в urlpatterns не буду содержать общий префикс. Однако, вы все равно можете использовать общий префикс, чтобы сократить дублирование кода. Просто используете несколько результатов вызова patterns() вместе:

Раньше:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^$', 'myapp.views.app_index'),
    url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$', 'myapp.views.month_display'),
    url(r'^tag/(?P<tag>\w+)/$', 'weblog.views.tag'),
)

Теперь:

from django.conf.urls import patterns, url

urlpatterns = patterns('myapp.views',
    url(r'^$', 'app_index'),
    url(r'^(?P<year>\d{4})/(?P<month>[a-z]{3})/$','month_display'),
)

urlpatterns += patterns('weblog.views',
    url(r'^tag/(?P<tag>\w+)/$', 'tag'),
)

Комбинирование URLconfs

В любой момент, ваш urlpatterns может “включать” другие модули URLconf.

Вот пример URLconf для сайта Django. Он включает множество других конфигураций URL:

from django.conf.urls import include, patterns, url

urlpatterns = patterns('',
    # ... snip ...
    url(r'^comments/', include('django.contrib.comments.urls')),
    url(r'^community/', include('django_website.aggregator.urls')),
    url(r'^contact/', include('django_website.contact.urls')),
    # ... snip ...
)

Заметим, что регулярные выражения не содержат $ (определитель конца строки), но содержит косую черту в конце. Каждый раз, когда Django встречает include() (django.conf.urls.include()), из URL обрезается уже совпавшая часть, остальное передается во включенный URLconf для дальнейшей обработки.

Еще один способ добавить дополнительные URL-шаблоны: указать в include() результат выполнения patterns(). Например:

from django.conf.urls import include, patterns, url

extra_patterns = patterns('',
    url(r'^reports/(?P<id>\d+)/$', 'credit.views.report'),
    url(r'^charge/$', 'credit.views.charge'),
)

urlpatterns = patterns('',
    url(r'^$', 'apps.main.views.homepage'),
    url(r'^help/', include('apps.help.urls')),
    url(r'^credit/', include(extra_patterns)),
)

В этом примере URL /credit/reports/ обработан представлением credit.views.report().

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

from django.conf.urls import patterns, url

urlpatterns = patterns('wiki.views',
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/history/$', 'history'),
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/edit/$', 'edit'),
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/discuss/$', 'discuss'),
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/permissions/$', 'permissions'),
)

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

from django.conf.urls import include, patterns, url

urlpatterns = patterns('',
    url(r'^(?P<page_slug>\w+)-(?P<page_id>\w+)/', include(patterns('wiki.views',
        url(r'^history/$', 'history'),
        url(r'^edit/$', 'edit'),
        url(r'^discuss/$', 'discuss'),
        url(r'^permissions/$', 'permissions'),
    ))),
)

Нахождение аргументов в URL

Включенный URLconf получает все аргументы найденные родительским URLconfs, по этому этот пример работает:

# In settings/urls/main.py
from django.conf.urls import include, patterns, url

urlpatterns = patterns('',
    url(r'^(?P<username>\w+)/blog/', include('foo.urls.blog')),
)

# In foo/urls/blog.py
from django.conf.urls import patterns, url

urlpatterns = patterns('foo.views',
    url(r'^$', 'blog.index'),
    url(r'^archive/$', 'blog.archive'),
)

В примере выше, найденный аргумент "username" передается во включенный URLconf, как и ожидалось.

Передача дополнительных аргументов в представление

Конфигурация URL-ов позволяет определить дополнительные аргументы для функции представления, используя словарь Python.

Функция django.conf.urls.url() может принимать третий необязательный элемент. Этот элемент является словарем, который определяет дополнительные именованные аргументы для функции представления.

Например:

from django.conf.urls import patterns, url

urlpatterns = patterns('blog.views',
    url(r'^blog/(?P<year>\d{4})/$', 'year_archive', {'foo': 'bar'}),
)

Например, при запросе к /blog/2005/, Django вызовет blog.views.year_archive(request, year='2005', foo='bar').

Такой подход используется в syndication framework для передачи параметров и дополнительных данных в представление.

Dealing with conflicts

Если регулярное выражение URL-шаблона выделяет из URL-а аргумент с названием, которое уже используется в дополнительных именованных аргументах, будет использован аргумент из словаря дополнительных аргументов, вместо значения из URL.

Передача дополнительных аргументов в include()

Аналогично вы можете передать дополнительные аргументы в include(). При этом, каждый URL-шаблон включенного URLconf будет дополнен этими дополнительными аргументами.

Например, эти два URLconf работают идентично:

Первый:

# main.py
from django.conf.urls import include, patterns, url

urlpatterns = patterns('',
    url(r'^blog/', include('inner'), {'blogid': 3}),
)

# inner.py
from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^archive/$', 'mysite.views.archive'),
    url(r'^about/$', 'mysite.views.about'),
)

Второй:

# main.py
from django.conf.urls import include, patterns, url

urlpatterns = patterns('',
    url(r'^blog/', include('inner')),
)

# inner.py
from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^archive/$', 'mysite.views.archive', {'blogid': 3}),
    url(r'^about/$', 'mysite.views.about', {'blogid': 3}),
)

Дополнительные аргументы всегда передаются каждому представлению во включенном URLconf, независимо от того, принимает оно эти аргументы или нет. По этому, такой подход полезен только если вы уверенны, что каждое представление принимает передаваемые аргументы.

Передача функций вместо строк

Некоторые разработчики предпочитают передавать функции вместо строк, содержащих путь для импорта. Такой способ также работает – вы можете передать любой вызываемый объект в качестве представлений.

Например, у нас есть такой URLconf:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    url(r'^archive/$', 'mysite.views.archive'),
    url(r'^about/$', 'mysite.views.about'),
    url(r'^contact/$', 'mysite.views.contact'),
)

Вы можете сделать то же самое, передавая объекты вместо строк. Просто импортируйте эти объекты:

from django.conf.urls import patterns, url
from mysite.views import archive, about, contact

urlpatterns = patterns('',
    url(r'^archive/$', archive),
    url(r'^about/$', about),
    url(r'^contact/$', contact),
)

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

from django.conf.urls import patterns, url
from mysite import views

urlpatterns = patterns('',
    url(r'^archive/$', views.archive),
    url(r'^about/$', views.about),
    url(r'^contact/$', views.contact),
)

Стиль, который вы используете, зависит от вас.

Стоит заметить, что при передаче объекта вместо строки, префикс для представлений (описанный выше `The view prefix`_) не будет иметь никакого эффекта.

Не забываем импоритровать представления-классы:

from django.conf.urls import patterns, url
from mysite.views import ClassBasedView

urlpatterns = patterns('',
    url(r'^myview/$', ClassBasedView.as_view()),
)

Поиск URL-а по URL-шаблону

Обычной задачей является получение URL-а по его определению для отображения пользователю или для редиректа.

Очень важно не “хардкодить” URL-ы (трудоемкая и плохо поддерживаемая стратегия). Иногда необходимо менять структуру URL-ов, при этом важно не оставить где-то URL в старом формате.

В общем необходимо предерживаться принципа DRY. Немаловажно иметь возможность менять URL-ы в одном месте, а не выполнять поиск и замену по всему проекту.

Для получения URL-а нам необходим его идентификатор, то есть название URL-шаблона, и позиционные и именованные аргументы.

В Django для работы с URL-ами используется так называемый “URL mapper”. Ему передается URLconf, и теперь его можно использовать в два направления:

  • Получая запрошенный URL находит необходимое представление и предоставляет все необходимые аргументы полученные из URL-а.

  • Получая идентификатор представления и передаваемые ему аргументы, возвращает URL.

Первое это то, что мы уже рассмотрели в предыдущем разделе. Второе называется URL reversing, в общем получение URL-а по его названию.

Django предоставляет инструменты для получения URL-ов в различных компонентах фреймверка:

  • В шаблонах: Использование шаблонного тега url.

  • В Python коде: Использование функции django.core.urlresolvers.reverse().

  • На более высоком уровне для привязки урлов к моделям - метод get_absolute_url().

Примеры

Рассмотрим следующий URLconf:

from django.conf.urls import patterns, url

urlpatterns = patterns('',
    #...
    url(r'^articles/(\d{4})/$', 'news.views.year_archive'),
    #...
)

В соответствии с ним архиву nnnn года соответствует URL /articles/nnnn/.

Вы можете получить его в шаблоне следующим образом:

<a href="{% url 'news.views.year_archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news.views.year_archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

В Python коде:

from django.core.urlresolvers import reverse
from django.http import HttpResponseRedirect

def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse('news.views.year_archive', args=(year,)))

Если по каким-либо причинам необходимо будет изменить URL, достаточно будет изменить запись в вашем URLconf.

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

Именованные URL-шаблоны

Обычная практика использовать одно представление для нескольких URL-шаблонов в URLconf. Например, эти два URL-шаблона указывают на представление archive:

from django.conf.urls import patterns, url
from mysite.views import archive

urlpatterns = patterns('',
    url(r'^archive/(\d{4})/$', archive),
    url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}),
)

Этот пример работает, но, если вы захотите найти URL (используя reverse() или тег шаблона url), это приведет к проблемам. Если вы захотите получить URL для представления archive, Django запутается так как два URL-шаблона соответствуют одному представлению.

Для решения этой проблемы, Django предоставляет именованные URL-шаблоны. То есть, вы можете дать название для URL-шаблонов, чтобы отличать их и использовать эти названия при поиске нужного вам URL-а.

Перепишем пример выше с использованием именованных URL-шаблонов:

from django.conf.urls import patterns, url
from mysite.views import archive

urlpatterns = patterns('',
    url(r'^archive/(\d{4})/$', archive, name="full-archive"),
    url(r'^archive-summary/(\d{4})/$', archive, {'summary': True}, name="arch-summary"),
)

Используя эти названия (full-archive и arch-summary), вы можете обратиться к каждому URL-шаблону отдельно:

{% url 'arch-summary' 1945 %}
{% url 'full-archive' 2007 %}

Хоть оба URL-шаблона ссылаются на одно представление archive, использование параметра name в теге django.conf.urls.url() позволит вам различить их в шаблоне.

Вы можете использовать любые символы в названии.

Примечание

При выборе названия для URL-шаблона, убедитесь что оно достаточно уникально. Если вы назовете URL-шаблон comment, и другое приложение сделает аналогичное, нет гарантии что в шаблон будет вставлен правильный URL.

Добавление префикса к названию URL-шаблона, возможного состоящего из названия приложения, уменьшит шанс конфликта. Мы советуем использовать myapp-comment вместо comment.

Пространства имен в конфигурации URL-ов

Описание

Если необходимо использовать несколько экземпляров одного приложения, было бы удобно иметь возможность различать их. Это особенно важно при использовании именованных шаблонов URL, так как несколько экземпляров используют одинаковые названия для URL-ов. Пространства имен позволяют сделать эти названия уникальными.

Пространство имен состоит из двух частей, каждая из которых это строка:

application namespace

Указывает название установленного приложения. Все экземпляры одного приложения будет иметь одно название. Например, название приложения администратора Django – admin.

instance namespace

Идентифицирует конкретный экземпляр приложения. Должно быть уникальным для проекта. Однако, название экземпляра может быть равным названию приложения. Оно используется по-умолчанию при создании приложения. Например, пространство имен приложения администратора Django – admin.

Пространство имен определяется с помощью оператора ':'. Например, главная страница интерфейса администратора определяется как 'admin:index'. Мы видим пространство имен 'admin', и название URL-шаблона 'index'.

Пространства имен могут быть вложенными. Название URL-а 'foo:bar:whiz' означает именованный URL-шаблон с названием 'whiz' в пространстве имен 'bar', которое было определенно в другом пространстве имен - 'foo'.

Поиск URL-а по шаблону с пространством имен

Если необходимо найти URL по названию с пространсвом имен (например, 'myapp:index'), Django разбивает название на части и следует такому алгоритму:

  1. Первым делом, Django проверяет название(пространсву имен) приложения (например, myapp). Django получает список экземпляров приложения.

  2. Если указан текущий экземпляр приложения, Django вернет “URL resolver” для этого экземпляра. Текущий экземпляр приложения можно указать используя атрибут current_app контекста шаблона. Приложения, которые будут использоваться в нескольких экземплярах в одном проекте, должны всегда определять атрибут current_app для Context или RequestContext, который используется для выполнения шаблона.

    Текущей экземпляр приложения можно также определить используя аргумент при вызове функции django.core.urlresolvers.reverse().

  3. Если текущий экземпляр приложения не найден, Django попытается использовать экземпляр по-умолчанию. Экземпляр по-умолчанию – это экземпляр, у которого название приложения и название экземпляра приложения совпадают (в нашем примере это экземпляр myapp с названием myapp).

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

  5. Если на первом шаге не было найдено приложение по указанному пространству имен, Django попытается найти экземпляр приложения по его названию, используя пространство имен как название экземпляра.

Если пространство имен вложенное, этот процесс будет повторен, пока неопределенным не останется только название представления. URL для названия представления будет искаться среди URL-шаблонов определенных в приложении, найденном через пространство имен.

Например

Разберем небольшой пример. У нас есть два экземпляра приложения myapp: один назван foo, другой - bar. myapp содержит главную страницу с названием URL-а index. Возможны такие ситуации:

  • Если один из экземпляров указан как текущий - например, мы выполняем шаблон в экземпляре bar - поиск URL-а по myapp:index вернет URL на главную страницу экземпляра приложения bar.

  • Если текущий экземпляр приложения не указан - например, мы ищем URL в другом приложении - поиск по 'myapp:index' вернет URL для последнего добавленного экземпляра 'myapp'. Это может быть 'foo' или 'bar', в зависимости от того, в каком порядке они были добавлены в URL-шаблоны проекта.

  • Поиск по 'foo:index' всегда вернет ссылку на главную страницу экземпляра приложения 'foo'.

Если бы был определен экземпляр по-умолчанию - то есть, экземпляр с названием 'myapp':

  • Если один из экземпляров указан как текущий - например, мы выполняем шаблон в экземпляре bar - поиск URL-а по myapp:index вернет URL на главную страницу экземпляра приложения bar.

  • Если текущий экземпляр приложения не указан - например, мы ищем URL в другом приложении - поиск по 'myapp:index' вернет URL на главную страницу экземпляра по-умолчанию.

  • Поиск по 'foo:index' все также вернет ссылку на главную страницу экземпляра приложения 'foo'.

Пространства имен в URL -ах и include

Пространство имен URL можно определить двумя путями.

Первый, передав в качестве аргументов при вызове django.conf.urls.include(). Например:

url(r'^help/', include('apps.help.urls', namespace='foo', app_name='bar')),

Этот код добавляет URL-шаблоны определенные в apps.help.urls, используя название приложения 'bar' и название экземпляра 'foo'.

Второй, вы можете добавить объект, который содержит все необходимые данные. Если использовать результат patterns() при вызове функции include(), он будет добавлен в глобальное пространство имен. Однако, в include() можно передать 3-элементный кортеж, который содержит:

(<patterns object>, <application namespace>, <instance namespace>)

Например:

from django.conf.urls import include, patterns, url

help_patterns = patterns('',
    url(r'^basic/$', 'apps.help.views.views.basic'),
    url(r'^advanced/$', 'apps.help.views.views.advanced'),
)

url(r'^help/', include(help_patterns, 'bar', 'foo')),

Этот код добавляет URL-шаблоны, используя название приложения bar и название экземпляра foo.

Такой подход используется при подключении приложения интерфейса администратора(admin) Django. Для подключения используется экземпляр AdminSite, каждый из которых содержит свойство urls. Оно возвращает URL-шаблоны, которые доступные для этого экземпляра. Это то свойство, которое вы добавляете, используя include(), в urlpatterns вашего проекта при установке приложения администратора.