Диспетчер 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().
- Экземпляр
- Если ни один 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-шаблон.
Например:
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, параллельные 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() сопоставляет количество аргументов и имена ключевых аргументов. Преобразователи путей также могут поднять ValueError для обозначения отсутствия соответствия, см. Регистрация пользовательских преобразователей путей для получения подробностей.
Пространства имён URL-адресов
Введение
Пространства имён URL-адресов позволяют вам однозначно обращаться к именованным шаблонам URL-адресов, даже если разные приложения используют одни и те же имена URL-адресов. Это хорошая практика для сторонних приложений всегда использовать пространственно-именованные URL-адреса (как мы делали в учебнике). Аналогично, это также позволяет вам обращаться к URL-адресам, если развернуты несколько экземпляров приложения. Другими словами, поскольку несколько экземпляров одного приложения будут использовать общие именованные URL-адреса, пространства имён позволяют отличить эти именованные URL-адреса.
Приложения Django, которые должным образом используют пространственные имена URL-адресов, могут быть развернуты более одного раза для конкретного сайта. Например, django.contrib.admin имеет класс AdminSite, который позволяет вам развернуть более одного экземпляра администратора. В последующем примере мы обсудим идею развертывания приложения опросов из учебника в двух разных местах, чтобы мы могли предоставить одну и ту же функциональность двум разным аудиториям (авторам и издателям).
Пространство имён URL-адресов состоит из двух частей, обе из которых являются строками:
-
application namespace - Это описывает имя приложения, которое развертывается. Каждый экземпляр одного приложения будет иметь то же самое пространство имён приложения. Например, приложение администратора Django имеет довольно предсказуемое пространство имён приложения
'admin'. -
instance namespace - Это идентифицирует конкретный экземпляр приложения. Пространства имён экземпляров должны быть уникальными во всем вашем проекте. Однако пространство имён экземпляра может быть таким же, как пространство имён приложения. Это используется для указания стандартного экземпляра приложения. Например, стандартный экземпляр администратора Django имеет пространство имён экземпляра
'admin'.
Пространственно-именованные URL-адреса указываются с использованием оператора ':'. Например, главная страница индекса приложения администратора ссылается на '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. Это будет'publisher-polls', поскольку он объявлен последним вurlpatterns. -
'author-polls:index'всегда будет преобразовано в главную страницу экземпляра'author-polls'(и аналогично для'publisher-polls').
Если также есть стандартный экземпляр — например, экземпляр с именем 'polls' — единственное изменение по сравнению с вышесказанным будет в случае, когда нет текущего экземпляра (вторый пункт в списке выше). В этом случае 'polls:index' будет преобразовано в главную страницу стандартного экземпляра вместо экземпляра, объявленного последним в urlpatterns.
Пространства имён URL и включённые URLconf
Пространства имён приложения включённых URLconf можно указать двумя способами.
Во-первых, вы можете установить атрибут app_name в модуле включённого 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')),
]
Определённые в polls.urls URL-адреса будут иметь пространство имён приложения 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. Это означает, что это также будет экземпляр по умолчанию для данного пространства имен.
© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/4.0/topics/http/urls/