Spec-Zone.ru › Django 6.0

Диспетчер URL

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

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

Обзор

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

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

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

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

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

  1. Django определяет корневой модуль URLconf, который нужно использовать. Обычно это значение настройки ROOT_URLCONF, но если у входящего объекта HttpRequest есть атрибут urlconf (установленный промежуточным ПО), вместо настройки ROOT_URLCONF будет использовано его значение.
  2. Django загружает этот модуль Python и ищет переменную urlpatterns. Это должна быть последовательность экземпляров 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.

Например:

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-([0-9]+)/)?$", blog_articles),  # bad
    re_path(r"^comments/(?:page-(?P<page_number>[0-9]+)/)?$", 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.

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

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

Синтаксис переменной 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 ниже других 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 (это трудоёмкий, плохо масштабируемый и подверженный ошибкам подход). Не менее опасно создавать специальные механизмы генерации 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>/.

Получить этот URL в коде шаблона можно так:

<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 разбивает полное имя на части и выполняет поиск в следующем порядке:

  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. Это будет 'publisher-polls', поскольку он указан последним в urlpatterns.
  • 'author-polls:index' всегда будет разрешён в главную страницу экземпляра 'author-polls' (то же относится и к 'publisher-polls').

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

Пространства имён URL и подключаемые конфигурации URL

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

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

polls/urls.py
from django.urls import path

from . import views

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

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

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

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

(<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(). Если пространство имён экземпляра не указано, по умолчанию будет использоваться пространство имён приложения подключаемой конфигурации URL. Это также означает, что оно станет экземпляром по умолчанию для этого пространства имён.

© Django Software Foundation and individual contributors
Licensed under the BSD License.
https://docs.djangoproject.com/en/6.0/topics/http/urls/

Spec-Zone.ru

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