Spec-Zone.ru › Django 3.2

Диспечер URL

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

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

Обзор

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

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

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

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

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

  1. Django определяет корневой модуль URLconf, который нужно использовать. Обычно это значение настройки ROOT_URLCONF, но если у объекта входящего HttpRequest есть атрибут urlconf (установленный middleware), его значение будет использоваться вместо значения настройки ROOT_URLCONF.
  2. Django загружает этот модуль Python и ищет переменную urlpatterns. Она должна быть последовательностью последовательности django.urls.path() и/или django.urls.re_path().
  3. Django последовательно перебирает каждый шаблон URL и останавливается на первом, который соответствует запрошенному URL, сопоставляя его с path_info.
  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 — соответствует любой строке slug, состоящей из букв или цифр ASCII, плюс символы тире и нижнего подчёркивания. Например, building-your-1st-django-site.
  • uuid — соответствует отформатированному UUID. Чтобы предотвратить сопоставление нескольких URL с одной страницей, тире должны быть включены, а буквы должны быть строчными. Например, 075194d3-6885-417e-a8a8-6c931e272f00. Возвращает экземпляр UUID.
  • path — соответствует любой непустой строке, включая разделитель пути, '/'. Это позволяет сопоставлять весь 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, параллельно с проектом 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 имеет довольно предсказуемое пространство имён приложения '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 разделяет полное имя на части и выполняет следующий поиск:

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

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

  3. Если нет текущего приложения, Django ищет приложение по умолчанию. Приложение по умолчанию — это экземпляр, у которого пространство имён экземпляра соответствует пространству имён приложения (в данном примере экземпляр polls с именем 'polls').
  4. Если нет экземпляра по умолчанию, Django выберет последний развернутый экземпляр приложения, независимо от его имени.
  5. Если указанное пространство имён не соответствует пространству имён приложения на шаге 1, Django попробует прямой поиск пространства имён как пространства имён экземпляра.

Если есть вложенные пространства имён, эти шаги повторяются для каждой части пространства имён, пока не останется только имя представления. Затем имя представления будет преобразовано в 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, который объявлен последним в 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')),
]

Определённые в polls.urls URL-адреса будут иметь пространство имён приложения 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.2/topics/http/urls/

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API