Диспетчер URL
Чистая и элегантная схема URL — важный элемент высококачественного веб-приложения. Django позволяет проектировать URL как угодно, без ограничений фреймворка.
См. Cool URIs don’t change, написанную создателем Всемирной паутины Тимом Бернерсом-Ли, для отличных аргументов в пользу того, почему URL должны быть чистыми и удобными для использования.
Обзор
Для проектирования URL приложения вы создаёте модуль Python, условно называемый URLconf (конфигурация URL). Этот модуль — чистый код Python и представляет собой отображение между выражениями пути URL и функциями Python (вашими представлениями).
Это отображение может быть коротким или длинным по мере необходимости. Оно может ссылаться на другие отображения. И, поскольку это чистый код Python, оно может быть построено динамически.
Django также предоставляет способ перевода URL в соответствии с активным языком. Для получения дополнительной информации см. документацию по интернационализации.
Как Django обрабатывает запрос
Когда пользователь запрашивает страницу на вашем сайте, работающем на Django, система выполняет следующий алгоритм, чтобы определить, какой код Python выполнить:
- Django определяет корневой модуль URLconf, который нужно использовать. Обычно это значение настройки
ROOT_URLCONF, но если объект входящегоHttpRequestимеет атрибутurlconf(установленный middleware), его значение будет использовано вместо настройкиROOT_URLCONF. - Django загружает этот модуль Python и ищет переменную
urlpatterns. Это должна быть последовательность последовательность объектовdjango.urls.path()и/илиdjango.urls.re_path(). - Django перебирает каждую шаблон URL в порядке и останавливается на первом, который соответствует запрошенному URL, сопоставляя его с
path_info. -
После того, как один из шаблонов URL сопоставляется, Django импортирует и вызывает указанное представление, которое является функцией Python (или представление на основе класса представление на основе класса). Представлению передаются следующие аргументы:
- Экземпляр
HttpRequest. - Если сопоставленный шаблон URL не содержал именованных групп, то совпадения из регулярного выражения передаются как позиционные аргументы.
-
Именованные аргументы состоят из любых именованных частей, сопоставленных выражением пути, которые предоставляются, переопределяемые любыми аргументами, указанными в необязательном аргументе
kwargsкdjango.urls.path()илиdjango.urls.re_path().Изменено в Django 3.0:В более старых версиях именованные аргументы с значениями
Noneсоздавались также для не предоставленных именованных частей.
- Экземпляр
- Если ни один шаблон 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— Сопоставляется с любой строкой slug, состоящей из латинских букв или цифр, а также символов тире и подчёркивания. Например,building-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, если другой шаблон URL не соответствует. -
Метод
to_url(self, value), который обрабатывает преобразование типа Python в строку, которая будет использоваться в URL. Он должен вызыватьValueErrorпри невозможности преобразования заданного значения.ValueErrorинтерпретируется как отсутствие совпадения, и в результатеreverse()вызоветNoReverseMatch, если другой шаблон URL не соответствует.Изменено в Django 3.1:Добавлена поддержка вызова
ValueErrorдля указания отсутствия совпадения.
Например:
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/ или в этом случае никаких аргументов, в то время как comments может быть обращен с помощью или отсутствия аргументов, или значения для 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 и представления:
# 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 должна быть последовательностью экземпляров path() и/или re_path().
Обработка ошибок
Когда Django не может найти соответствие для запрошенного URL-адреса или при возникновении исключения, Django вызывает представление для обработки ошибок.
Представления, используемые для этих случаев, задаются четырьмя переменными. Их значения по умолчанию должны подойти для большинства проектов, но можно выполнить дальнейшую настройку, переопределяя их значения по умолчанию.
См. документацию по настройке представлений ошибок для получения полной информации.
Эти значения можно установить в вашем корневом URLconf. Установка этих переменных в любом другом URLconf не окажет никакого эффекта.
Значения должны быть вызываемыми объектами или строками, представляющими полный путь импорта Python к представлению, которое должно вызываться для обработки данной ситуации ошибки.
Переменные:
-
handler400— См.django.conf.urls.handler400. -
handler403— См.django.conf.urls.handler403. -
handler404— См.django.conf.urls.handler404. -
handler500— См.django.conf.urls.handler500.
Включение других URLconf
В любой момент ваш urlpatterns может «включить» другие модули URLconf. Это фактически «устанавливает корень» набора URL-адресов под другими.
Например, вот фрагмент URLconf для самого сайта Django. Он включает в себя ряд других URLconf:
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().
Это можно использовать для устранения избыточности из URLconf, где один префикс пути используется многократно. Например, рассмотрим этот 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 получает любые захваченные параметры из родительских URLconf, поэтому следующий пример допустим:
# 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, как ожидалось.
Передача дополнительных параметров функциям представления
URLconf имеет возможность передачи дополнительных аргументов функциям представлений в качестве словаря 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-адреса (трудоёмкий, не масштабируемый и подверженный ошибкам подход). Не менее опасен разработанный ad-hoc механизм генерации URL-адресов, параллельный разработанному в URLconf, что может привести к созданию URL-адресов, которые со временем устаревают.
Другими словами, требуется механизм DRY. Среди прочих преимуществ он позволит эволюционировать структуру 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() сопоставляет количество аргументов и имена ключевых аргументов. Преобразователи путей также могут поднимать ValueError для указания отсутствия совпадения, см. Регистрация пользовательских преобразователей путей для получения подробностей.
Пространства имён URL
Введение
Пространства имён URL позволяют уникально обращаться к именованным URL-образцам, даже если разные приложения используют одни и те же имена URL. Это хорошая практика для сторонних приложений всегда использовать именованные URL (как мы делали в учебнике). Аналогично, это также позволяет вам обращаться к URL-адресам, если развернуты несколько экземпляров приложения. Другими словами, поскольку несколько экземпляров одного приложения будут использовать общие именованные URL, пространства имён предоставляют способ отличить эти именованные URL.
Приложения Django, которые должным образом используют пространства имён URL, могут быть развернуты более одного раза для конкретного сайта. Например, django.contrib.admin имеет класс AdminSite, который позволяет вам развернуть более одного экземпляра администратора. В последующем примере мы обсудим идею развертывания приложения опросов из учебника в двух разных местах, чтобы мы могли предоставлять одинаковые функции двум разным аудиториям (авторам и издателям).
Пространство имён URL состоит из двух частей, обе из которых являются строками:
-
application namespace - Это описывает имя приложения, которое развертывается. Каждый экземпляр одного приложения будет иметь одинаковое имя пространства имён приложения. Например, приложение Django admin имеет довольно предсказуемое пространство имён приложения
'admin'. -
instance namespace - Это идентифицирует конкретный экземпляр приложения. Имена пространств экземпляров должны быть уникальными для всего вашего проекта. Однако имя пространства экземпляра может совпадать с именем пространства приложения. Это используется для указания по умолчанию экземпляра приложения. Например, стандартный экземпляр Django admin имеет пространство имён экземпляра
'admin'.
Именованные URL указываются с помощью оператора ':'. Например, главная страница индекса приложения admin ссылается на 'admin:index'. Это указывает на пространство имён 'admin', и именованный URL 'index'.
Пространства имён также могут быть вложенными. Именной URL 'sports:polls:index' будет искать образец с именем 'index' в пространстве имён 'polls', которое само по себе определено в главном пространстве имён 'sports'.
Обратное преобразование именованных URL
При решении именованного URL (например, 'polls:index') Django разбивает полное квалифицированное имя на части и затем выполняет следующий поиск:
- Сначала Django ищет соответствующее пространство имён приложения (в этом примере,
'polls'). Это даст список экземпляров этого приложения. -
Если определено текущее приложение, Django находит и возвращает решатель URL для этого экземпляра. Текущее приложение можно указать с помощью аргумента
current_appк функцииreverse().Тэги шаблона
urlиспользуют пространство имён текущего разрешённого представления в качестве текущего приложения вRequestContext. Вы можете переопределить этот параметр по умолчанию, установив текущее приложение в атрибутеrequest.current_app. - Если текущее приложение не определено, Django ищет приложение по умолчанию. Приложение по умолчанию — это экземпляр, имеющий пространство имён экземпляра, совпадающее с пространством имён приложения (в этом примере, экземпляр
pollsс именем'polls'). - Если приложение по умолчанию не определено, Django выберет последний развернутый экземпляр приложения, какое бы имя экземпляра оно ни имело.
- Если указанное пространство имён не соответствует пространству имён приложения на шаге 1, Django попытается выполнить прямой поиск пространства имён как пространства имён экземпляра.
Если имеются вложенные пространства имён, эти шаги повторяются для каждой части пространства имён, пока не останется только имя представления. Затем имя представления будет преобразовано в URL в найденном пространстве имён.
Пример
Чтобы продемонстрировать стратегию разрешения, рассмотрим пример двух экземпляров приложения polls из учебника: одного с именем 'author-polls' и одного с именем 'publisher-polls'. Предположим, что мы расширили это приложение таким образом, чтобы оно учитывало имя пространства экземпляра при создании и отображении опросов.
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')),
]
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, который зарегистрирован последним вurlpatterns. -
'author-polls:index'всегда будет преобразовано в главную страницу экземпляра'author-polls'(и аналогично для'publisher-polls').
Если также был бы экземпляр по умолчанию — например, экземпляр с именем 'polls' — единственным изменением по сравнению с вышеизложенным было бы в случае, когда нет текущего экземпляра (второй пункт в списке выше). В этом случае 'polls:index' будет преобразовано в главную страницу экземпляра по умолчанию вместо экземпляра, объявленного последним в urlpatterns.
Пространства имён URL и включенные URLconf
Пространства имён включённых URLconf можно задавать двумя способами.
Во-первых, вы можете установить атрибут app_name в модуле URLconf, включённом в URLconf, на том же уровне, что и атрибут urlpatterns. Вы должны передать фактический модуль или строковое указание на модуль в include(), а не сам список urlpatterns.
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'),
...
]
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
]
У URL-адресов, определённых в polls.urls , будет применено прикладное пространство имён polls.
Во-вторых, вы можете включить объект, содержащий данные встроенного пространства имён. Если вы include() список экземпляров path() или re_path(), URL-адреса, содержащиеся в этом объекте, будут добавлены к глобальному пространству имён. Однако, вы также можете include() пару из двух элементов, содержащую:
(<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. Это также будет значением по умолчанию для данного пространства имён.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/3.1/topics/http/urls/