Spec-Zone.ru › Django 5.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 (установленный средством), его значение будет использоваться вместо настройки 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 — Сопоставляет любую строку-пометку, состоящую из букв или цифр 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),
    ...,
]

Устарело начиная с версии 5.1: Переопределение существующих преобразователей с помощью django.urls.register_converter() устарело.

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

Если синтаксис путей и преобразователей недостаточно для определения ваших шаблонов 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-адресов ниже других.

Например, вот фрагмент 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. Другой необходимой информацией для поиска правильного 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, который позволяет вам развернуть более одного экземпляра админки. В последующем примере мы обсудим идею развертывания приложения polls из учебника в двух разных местах, чтобы предоставить одну и ту же функциональность двум разным аудиториям (авторам и издателям).

Пространство имён 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 и включённые URLconf

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

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

polls/urls.py
from django.urls import path

from . import views

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

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

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

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

(<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/5.2/topics/http/urls/

Spec-Zone.ru

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