Диспетчер URL

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

Смотрите Классные URI не меняются от создателя World Wide Web Тима Бернерса-Ли, где приведены убедительные аргументы в пользу того, почему URL-адреса должны быть чистыми и удобными.

Overview

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

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

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

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

Когда пользователь запрашивает страницу вашего сайта на Django, система следует этому алгоритму, чтобы определить, какой код Python выполнить:

  1. Django определяет используемый корневой модуль URLconf. Обычно это значение параметра ROOT_URLCONF, но если входящий объект HttpRequest имеет атрибут urlconf (установленный промежуточным программным обеспечением), его значение будет использоваться вместо параметра ROOT_URLCONF.
  2. Django загружает этот модуль Python и ищет переменную urlpatterns. Это должна быть sequence (последовательность( экземпляров django.urls.path() и/или django.urls.re_path().
  3. Django проходит по каждому шаблону URL по порядку и останавливается на первом, который соответствует запрошенному URL.
  4. Как только один из шаблонов URL совпадает, Django импортирует и вызывает заданное представление, которое является простой функцией Python (или представление на основе классов). Представлению передаются следующие аргументы:
    • Экземпляр HttpRequest.
    • Если совпавший шаблон URL не вернул именованных групп, то совпадения из регулярного выражения предоставляются как позиционные аргументы.
    • Ключевые аргументы состоят из любых именованных частей, соответствующих выражению пути, переопределенных любыми аргументами, указанными в необязательном аргументе kwargs для django.urls.path() или django.urls.re_path().
  5. Если шаблон URL-адреса не совпадает или если на каком-либо этапе этого процесса возникает исключение, Django вызывает соответствующее представление обработки ошибок. Смотрите раздел Обработка ошибок ниже.

Пример

Вот пример URLconf:

from django.urls import path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<int:year>/', views.year_archive),
    path('articles/<int:year>/<int:month>/', views.month_archive),
    path('articles/<int:year>/<int:month>/<slug:slug>/', views.article_detail),
]

Примечания:

  • Чтобы получить значение из URL-адреса, используйте угловые скобки.
  • Захваченные значения могут дополнительно включать тип преобразователя. Например, используйте <int:name> для захвата целочисленного параметра. Если конвертер не включен, сопоставляется любая строка, за исключением символа /.
  • Нет необходимости добавлять косую черту в начале, потому что она есть в каждом URL. Например, это articles, а не /articles.

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

  • Запрос к /articles/2005/03/ будет соответствовать третьей записи в списке. Django вызовет функцию views.month_archive(request, year=2005, month=3).
  • /articles/2003/ будет соответствовать первому шаблону в списке, а не второму, потому что шаблоны проверяются по порядку, а первый - первый тест, который нужно пройти. Не стесняйтесь использовать порядок для вставки таких особых случаев. Здесь Django вызовет функцию views.special_case_2003(request)
  • /articles/2003 не соответствует ни одному из этих шаблонов, потому что каждый шаблон требует, чтобы URL-адрес заканчивался косой чертой.
  • /articles/2003/03/building-a-django-site/ будет соответствовать окончательному шаблону. Django вызвал бы функцию views.article_detail(request, year=2003, month=3, slug="building-a-django-site").

Конвертеры пути

По умолчанию доступны следующие конвертеры пути:

  • str - соответствует любой непустой строке, за исключением разделителя пути, '/'. Это значение по умолчанию, если преобразователь не включен в выражение.
  • int - соответствует нулю или любому положительному целому числу. Возвращает int.
  • slug - соответствует любой строке заголовка, состоящей из букв или цифр ASCII, а также символов дефиса и подчеркивания. Например, build-your-1st-django-site.
  • uuid - соответствует форматированному UUID. Чтобы предотвратить сопоставление нескольких URL-адресов с одной и той же страницей, необходимо использовать дефисы, а буквы должны быть строчными. Например, 075194d3-6885-417e-a8a8-6c931e272f00. Возвращает экземпляр UUID.
  • path - соответствует любой непустой строке, включая разделитель пути, '/'. Это позволяет вам сопоставлять полный путь URL, а не просто сегмент пути URL, как в случае с str.

Регистрация пользовательских конвертеров пути

Для более сложных требований соответствия вы можете определить свои собственные преобразователи пути.

Конвертер - это класс, который включает в себя следующее:

  • Атрибут класса regex в виде строки.
  • Метод to_python(self, value), который обрабатывает преобразование согласованной строки в тип, который должен быть передан в функцию. Он должен вызвать ValueError, если он не может преобразовать данное значение. ValueError интерпретируется как несоответствие, и, как следствие, пользователю отправляется ответ 404.
  • Метод to_url(self, value), который обрабатывает преобразование типа Python в строку, которая будет использоваться в URL-адресе.

Например:

class FourDigitYearConverter:
    regex = '[0-9]{4}'

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return '%04d' % value

Зарегистрируйте пользовательские классы конвертера в вашем URLconf, используя register_converter():

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, 'yyyy')

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    path('articles/<yyyy:year>/', views.year_archive),
    ...
]

Использование регулярных выражений

Если синтаксиса путей и преобразователей недостаточно для определения шаблонов URL-адресов, вы также можете использовать регулярные выражения. Для этого используйте re_path() вместо path().

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

Вот пример URLconf из предыдущего, переписанный с использованием регулярных выражений:

from django.urls import path, re_path

from . import views

urlpatterns = [
    path('articles/2003/', views.special_case_2003),
    re_path(r'^articles/(?P<year>[0-9]{4})/$', views.year_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$', views.month_archive),
    re_path(r'^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$', views.article_detail),
]

Это примерно то же самое, что и в предыдущем примере, за исключением:

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

При переключении с path() на re_path() или наоборот, особенно важно знать, что тип аргументов представления может измениться, и поэтому вы может потребоваться адаптировать ваши отображения (функции).

Использование безымянных групп регулярных выражений

Также как и с синтаксисом именованной группы, например (?P<year>[0-9]{4}), вы также можете использовать более короткую безымянную группу, например ([0-9]{4}).

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

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

Вложенные аргументы

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

from django.urls import re_path

urlpatterns = [
    re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                  # bad
    re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments),  # good
]

Оба шаблона используют вложенные аргументы и разрешаются: например, blog/page-2/ приведет к совпадению с blog_articles с двумя позиционными аргументами: page-2/ и 2. . Второй шаблон для ``comments будет соответствовать comments/page-2/ с ключевым аргументом page_number, установленным в 2. Внешний аргумент в этом случае является аргументом без захвата (?:...).

Для представления blog_articles необходимо, чтобы внешний захваченный аргумент был изменен на противоположный, page-2/ или без аргументов в этом случае, в то время как для комментариев можно обратить либо без аргументов, либо со значением для page_number.

Вложенные захваченные аргументы создают сильную связь между аргументами представления и URL-адресом, как показано на примере blog_articles: представление получает часть URL-адреса (page-2/), а не только значение, которое интересует представление. Эта связь еще более выражена при реверсировании, так как для переворота представления нам нужно передать часть URL вместо номера страницы.

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

Что ищет URLconf

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

Например, в запросе на https://www.example.com/myapp/URLconf будет искать myapp/.

В запросе на https://www.example.com/myapp/?page=3 URLconf будет искать myapp/.

URLconf не смотрит на метод запроса. Другими словами, все методы запроса - POST, GET, HEAD и т.д. - будут перенаправлены на одну и ту же функцию для одного и того же URL.

Определение значений по умолчанию для аргументов представлений

Удобный трюк - указать параметры по умолчанию для аргументов ваших представлений. Вот пример URLconf и view:

# URLconf
from django.urls import path

from . import views

urlpatterns = [
    path('blog/', views.page),
    path('blog/page<int:num>/', views.page),
]

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

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

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

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

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

urlpatterns должен быть sequence (последовательностью) экземпляров path() и/или re_path().

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

Когда Django не может найти соответствие для запрошенного URL или когда возникает исключение, Django вызывает представление обработки ошибок.

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

Смотрите документацию по настройка представлений ошибок для получения полной информации.

Такие значения можно установить в корневом URLconf. Установка этих переменных в любом другом URLconf не даст никакого эффекта.

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

Переменные:

Включение других URLconfs

В любой момент ваши urlpatterns могут «включать» другие модули URLconf. По сути, это «корень» набора нижестоящих URL-адресов.

Например, вот выдержка из URLconf для самого сайта Django. Он включает ряд других URLconfs:

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path('community/', include('aggregator.urls')),
    path('contact/', include('contact.urls')),
    # ... snip ...
]

Всякий раз, когда Django встречает include(), он отрезает любую часть URL-адреса, совпадающую до этого момента, и отправляет оставшуюся строку во включенный URLconf для дальнейшей обработки.

Другая возможность - включить дополнительные шаблоны URL-адресов, используя список экземпляров path(). Например, рассмотрим этот URLconf:

from django.urls import include, path

from apps.main import views as main_views
from credit import views as credit_views

extra_patterns = [
    path('reports/', credit_views.report),
    path('reports/<int:id>/', credit_views.report),
    path('charge/', credit_views.charge),
]

urlpatterns = [
    path('', main_views.homepage),
    path('help/', include('apps.help.urls')),
    path('credit/', include(extra_patterns)),
]

В этом примере URL-адрес /credit/reports/ будет обрабатываться представлением Django credit_views.report().

Это можно использовать для удаления избыточности из URLconfs, где один префикс шаблона используется многократно. Например, рассмотрим этот URLconf:

from django.urls import path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/history/', views.history),
    path('<page_slug>-<page_id>/edit/', views.edit),
    path('<page_slug>-<page_id>/discuss/', views.discuss),
    path('<page_slug>-<page_id>/permissions/', views.permissions),
]

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

from django.urls import include, path
from . import views

urlpatterns = [
    path('<page_slug>-<page_id>/', include([
        path('history/', views.history),
        path('edit/', views.edit),
        path('discuss/', views.discuss),
        path('permissions/', views.permissions),
    ])),
]

Захваченные параметры

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

# In settings/urls/main.py
from django.urls import include, path

urlpatterns = [
    path('<username>/blog/', include('foo.urls.blog')),
]

# In foo/urls/blog.py
from django.urls import path
from . import views

urlpatterns = [
    path('', views.blog.index),
    path('archive/', views.blog.archive),
]

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

Передача дополнительных параметров функции предствления

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

Функция path() может принимать необязательный третий аргумент, который должен быть словарем дополнительных ключевых аргументов для передачи в функцию представление.

Например:

from django.urls import path
from . import views

urlpatterns = [
    path('blog/<int:year>/', views.year_archive, {'foo': 'bar'}),
]

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

Этот метод используется в фреймворке синдикации для передачи метаданных и параметров представлениям.

Разрешение конфликтов

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

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

Точно так же вы можете передать дополнительные параметры в include(), и каждой строке во включенном URLconf будут переданы дополнительные параметры.

Например, эти два набора URLconf функционально идентичны:

Установите один:

# main.py
from django.urls import include, path

urlpatterns = [
    path('blog/', include('inner'), {'blog_id': 3}),
]

# inner.py
from django.urls import path
from mysite import views

urlpatterns = [
    path('archive/', views.archive),
    path('about/', views.about),
]

Установите второй:

# main.py
from django.urls import include, path
from mysite import views

urlpatterns = [
    path('blog/', include('inner')),
]

# inner.py
from django.urls import path

urlpatterns = [
    path('archive/', views.archive, {'blog_id': 3}),
    path('about/', views.about, {'blog_id': 3}),
]

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

Обратное разрешение URL-адресов

Распространенной потребностью при работе над проектом Django является возможность получения URL-адресов в их окончательных формах либо для встраивания в сгенерированный контент (URL-адреса представлений и ресурсов, URL-адреса, отображаемые пользователю и т.д.), либо для обработки потока навигации на сервере (перенаправления и т.д.)

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

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

Основная информация, доступная для получения URL-адреса – это идентификация (например, имя) представления, отвечающего за его обработку. Другая часть информации, которая обязательно должна участвовать в поиске правильного URL, – это типы (позиционные, ключевые слова) и значения аргументов представления.

Django предоставляет решение, в котором преобразователь URL-адресов является единственным хранилищем дизайна URL-адресов. Вы загружаете его с помощью своего URLconf, и затем его можно использовать в обоих направлениях:

  • Начиная с URL-адреса, запрошенного пользователем/браузером, он вызывает правильное представление Django, предоставляя любые аргументы, которые могут ему понадобиться, с их значениями, извлеченными из URL-адреса.
  • Начиная с идентификации соответствующего представления Django и значений аргументов, которые будут ему переданы, получите связанный URL.

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

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

  • В шаблонах: использование тега шаблона url.
  • В коде Python: использование функции reverse().
  • В коде более высокого уровня, связанном с обработкой URL-адресов экземпляров модели Django: метод get_absolute_url().

Примеры

Снова рассмотрим эту запись URLconf:

from django.urls import path

from . import views

urlpatterns = [
    #...
    path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
    #...
]

В соответствии с этой схемой URL для архива, соответствующего году nnnn, - это /articles/<nnnn>/.

Вы можете получить их в коде шаблона, используя:

<a href="{% url 'news-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-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

Или в коде Python:

from django.http import HttpResponseRedirect
from django.urls import reverse

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

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

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

Именование шаблонов URL

Чтобы выполнить реверсирование URL, вам необходимо использовать именованные шаблоны URL, как это сделано в примерах выше. Строка, используемая для имени URL, может содержать любые символы. Вы не ограничены допустимыми именами Python.

При именовании шаблонов URL-адресов выбирайте имена, которые вряд ли будут конфликтовать с выбором имен других приложений. Если вы называете свой шаблон URL-comment, а другое приложение делает то же самое, URL-адрес, который находит reverse(), зависит от того, какой шаблон последним присутствует в urlpatterns вашего проекта.

Добавление префикса к именам URL-адресов, возможно, производных от имени приложения (например, myapp-comment вместо comment), снижает вероятность коллизий.

Вы можете сознательно выбрать то же имя URL, что и другое приложение, если хотите переопределить представление. Например, обычным вариантом использования является переопределение LoginView. Некоторые части Django и большинства сторонних приложений предполагают, что это представление имеет шаблон URL-адреса с именем login. Если у вас есть настраиваемое представление входа в систему и его URL-адрес имеет имя login, reverse() найдет ваше настраиваемое представление, если оно находится в urlpatterns после django.contrib.auth.urls (если он вообще включен).

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

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

Вступление

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

Приложения Django, которые правильно используют пространство имен URL-адресов, могут быть развернуты более одного раза для определенного сайта. Например django.contrib.admin имеет класс AdminSite, который позволяет вам легко развернуть более одного экземпляра admin. В следующем примере мы обсудим идею развертывания приложения для опросов из учебника в двух разных местах, чтобы мы могли предоставить одни и те же функции двум разным аудиториям (авторам и издателям).

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

пространство имен приложения
Оно описывает имя развертываемого приложения. Каждый экземпляр одного приложения будет иметь одно и то же пространство имен приложения. Например, приложение администратора Django имеет в некоторой степени предсказуемое пространство имен приложения 'admin'.
пространство имен экземпляра
Оно определяет конкретный экземпляр приложения. Пространства имен экземпляров должны быть уникальными для всего вашего проекта. Однако пространство имен экземпляра может быть таким же, как пространство имен приложения. Это используется для указания экземпляра приложения по умолчанию. Например, экземпляром администратора Django по умолчанию имеет пространство имен экземпляра 'admin'.

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

Пространства имен также могут быть вложенными. Именованный URL-адрес 'sports:polls:index' будет искать шаблон с именем 'index' в пространстве имен 'polls', который сам определен в пространстве имен верхнего уровня 'sports'.

Реверсирование пространств имён URL

Получив URL-адрес с пространством имен (например, 'polls:index') для разрешения, Django разбивает полное имя на части, а затем пытается выполнить следующий поиск:

  1. Сначала Django ищет соответствующий application namespace (в этом примере 'polls'). Это даст список экземпляров этого приложения.

  2. Если определено текущее приложение, Django находит и возвращает преобразователь URL-адресов для этого экземпляра. Текущее приложение можно указать с помощью аргумента current_app функции reverse().

    Тег шаблона url использует пространство имен текущего разрешенного представления в качестве текущего приложения в RequestContext. Вы можете изменить это значение по умолчанию, установив для текущего приложения атрибут request.current_app.

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

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

  5. Если предоставленное пространство имен не соответствует application namespace на шаге 1, Django попытается выполнить прямой поиск пространства имен как instance namespace.

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

Пример

Чтобы продемонстрировать эту стратегию разрешения проблем в действии, рассмотрим пример двух экземпляров приложения polls из учебника: один под названием 'author-polls', а другой - publisher-polls'. Предположим, мы улучшили это приложение, чтобы оно учитывало пространство имен экземпляра при создании и отображении опросов.

urls.py
from django.urls import include, path

urlpatterns = [
    path('author-polls/', include('polls.urls', namespace='author-polls')),
    path('publisher-polls/', include('polls.urls', namespace='publisher-polls')),
]
polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]

Используя эту настройку, возможны следующие поиски:

  • Если один из экземпляров является текущим - скажем, если бы мы отображали страницу сведений в экземпляре 'author-polls' - 'polls: index' преобразуется в индексную страницу 'author-polls'; то есть оба следующих результата приведут к "/author-polls/".

    В методе представления на основе классов:

    reverse('polls:index', current_app=self.request.resolver_match.namespace)
    

    и в шаблоне:

    {% url 'polls:index' %}
    
  • Если текущего экземпляра нет - скажем, если мы отображали страницу где-то еще на сайте, - 'polls:index' будет преобразовываться в последний зарегистрированный экземпляр polls. Поскольку нет экземпляра по умолчанию (пространство имен экземпляров 'polls'), будет использоваться последний зарегистрированный экземпляр polls. Это будет 'publisher-polls', поскольку он объявлен последним в urlpatterns.

  • 'author-polls:index' всегда будет преобразовываться в индексную страницу экземпляра 'author-polls' (и аналогично для 'publisher-polls').

Если бы также существовал экземпляр по умолчанию, то есть экземпляр с именем 'polls', единственное изменение из приведенного выше было бы в случае, если нет текущего экземпляра (второй элемент в списке выше). В этом случае 'polls:index' будет разрешаться в индексную страницу экземпляра по умолчанию вместо экземпляра, объявленного последним в urlpatterns.

Пространства имен URL и включенные URLconfs

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

Во-первых, вы можете установить атрибут app_name во включенном модуле URLconf на том же уровне, что и атрибут urlpatterns. Вы должны передать фактический модуль или строковую ссылку на модуль в include(), а не сам список urlpatterns.

polls/urls.py
from django.urls import path

from . import views

app_name = 'polls'
urlpatterns = [
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
    ...
]
urls.py
from django.urls import include, path

urlpatterns = [
    path('polls/', include('polls.urls')),
]

URL-адреса, определенные в polls.urls, будут иметь пространство имен приложения polls.

Во-вторых, вы можете включить объект, содержащий данные встроенного пространства имен. Если вы include() список экземпляров path() или re_path(), URL-адреса, содержащиеся в этом объекте, будут добавлены в глобальное пространство имен . Однако вы также можете include() кортеж из 2, содержащий:

(<list of path()/re_path() instances>, <application namespace>)

Например:

from django.urls import include, path

from . import views

polls_patterns = ([
    path('', views.IndexView.as_view(), name='index'),
    path('<int:pk>/', views.DetailView.as_view(), name='detail'),
], 'polls')

urlpatterns = [
    path('polls/', include(polls_patterns)),
]

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

Пространство имен экземпляра можно указать с помощью аргумента namespace для include(). Если пространство имен экземпляра не указано, по умолчанию будет использоваться пространство имен приложения включенного URLconf. Это означает, что он также будет экземпляром по умолчанию для этого пространства имен.

Вернуться на верх