Spec-Zone.ru › Django 4.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 — Сопоставляет любую строку-слово, состоящую из букв или цифр ASCII, плюс тире и символ подчёркивания. Например, building-your-1st-django-site.
  • uuid — Сопоставляет отформатированный UUID. Чтобы избежать совпадения нескольких URL с одной и той же страницей, дефисы должны быть включены, а буквы — строчными. Например, 075194d3-6885-417e-a8a8-6c931e272f00. Возвращает экземпляр UUID.
  • path — Сопоставляет любую непустую строку, включая разделитель путей, '/'. Это позволяет сопоставлять весь путь URL, а не сегмент пути URL, как с str.

Регистрация пользовательских преобразователей путей

Для более сложных требований к соответствию вы можете определить собственные преобразователи путей.

Преобразователь — это класс, который включает следующее:

  • Атрибут класса regex, как строка.
  • Метод to_python(self, value), который обрабатывает преобразование сопоставленной строки в тип, который должен быть передан функции представления. Он должен вызвать исключение ValueError если не удаётся преобразовать заданное значение. Значение ValueError интерпретируется как отсутствие соответствия, и в следствие чего пользователю отправляется ответ 404, если другой шаблон URL не соответствует.
  • Метод to_url(self, value), который обрабатывает преобразование типа Python в строку, используемую в URL. Он должен вызвать исключение ValueError если не удаётся преобразовать заданное значение. Значение ValueError интерпретируется как отсутствие соответствия, и как следствие reverse() вызовет исключение NoReverseMatch, если другой шаблон URL не соответствует.

Например:

class FourDigitYearConverter:
    regex = "[0-9]{4}"

    def to_python(self, value):
        return int(value)

    def to_url(self, value):
        return "%04d" % value

Зарегистрируйте пользовательские классы преобразователей в вашем URLconf, используя register_converter():

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, "yyyy")

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    path("articles/<yyyy:year>/", views.year_archive),
    ...,
]

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

Если синтаксис путей и преобразователей недостаточно для определения ваших шаблонов URL, вы также можете использовать регулярные выражения. Для этого используйте re_path() вместо path().

В Python синтаксис именованных групп регулярных выражений — (?P<name>pattern), где name — имя группы, а pattern — какой-то шаблон для сопоставления.

Вот пример URLconf из предыдущего примера, переписанный с использованием регулярных выражений:

from django.urls import path, re_path

from . import views

urlpatterns = [
    path("articles/2003/", views.special_case_2003),
    re_path(r"^articles/(?P<year>[0-9]{4})/$", views.year_archive),
    re_path(r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/$", views.month_archive),
    re_path(
        r"^articles/(?P<year>[0-9]{4})/(?P<month>[0-9]{2})/(?P<slug>[\w-]+)/$",
        views.article_detail,
    ),
]

Это делает примерно то же, что и предыдущий пример, за исключением:

  • Совпадающие URL несколько более ограничены. Например, год 10000 больше не будет соответствовать, так как целые числа года ограничены четырьмя цифрами.
  • Каждый захваченный аргумент передаётся представлению как строка, независимо от того, какой вид соответствия создаёт регулярное выражение.

При переключении с использования path() на re_path() или наоборот, важно помнить, что тип аргументов представления может измениться, и поэтому вам может потребоваться адаптировать свои представления.

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

Помимо синтаксиса именованных групп, например (?P<year>[0-9]{4}), вы также можете использовать сокращённый синтаксис безымянных групп, например ([0-9]{4}).

Это не особенно рекомендуется, так как это упрощает случайную ошибку между предполагаемым смыслом соответствия и аргументами представления.

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

Вложенные аргументы

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

from django.urls import re_path

urlpatterns = [
    re_path(r"^blog/(page-([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-адресов, параллельных структуре, описанной в URLconf, что может привести к созданию устаревших URL-адресов со временем.

Другими словами, нужен механизм DRY. Среди прочих преимуществ он позволит эволюционировать структуру URL-адресов, не просматривая весь исходный код проекта для поиска и замены устаревших URL-адресов.

Основная информация для получения URL-адреса – это идентификатор (например, имя) представления, отвечающего за его обработку. Другие необходимые части информации для поиска нужного URL-адреса – типы (позиционные, ключевые) и значения аргументов представления.

Django предоставляет решение, в котором маппер URL-адресов является единственным хранилищем структуры URL-адресов. Вы передаёте ему свой URLconf, а затем он может использоваться в обоих направлениях:

  • Начиная с URL-адреса, запрошенного пользователем/браузером, он вызывает соответствующее представление Django, предоставляя любые необходимые аргументы со значениями, извлечёнными из URL-адреса.
  • Начиная с идентификатора соответствующего представления Django плюс значения аргументов, которые будут переданы в него, получите связанный URL-адрес.

Первый случай – это то, о чём мы говорили в предыдущих разделах. Второй случай – это то, что известно как обратный поиск URL-адресов, сопоставление обратных URL-адресов, обратный поиск URL-адресов или просто обратный поиск URL-адресов.

Django предоставляет инструменты для выполнения обратного поиска URL-адресов, которые соответствуют различным уровням, где требуются URL-адреса:

  • В шаблонах: использование тега шаблона url.
  • В коде Python: использование функции reverse().
  • В коде более высокого уровня, связанном с обработкой URL-адресов экземпляров моделей Django: метод get_absolute_url().

Примеры

Рассмотрим снова запись URLconf:

from django.urls import path

from . import views

urlpatterns = [
    # ...
    path("articles/<int:year>/", views.year_archive, name="news-year-archive"),
    # ...
]

Согласно этому проектированию, URL-адрес архива, соответствующего году nnnn, составляет /articles/<nnnn>/.

Вы можете получить эти данные в коде шаблона, используя:

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>
{# Or with the year in a template context variable: #}
<ul>
{% for yearvar in year_list %}
<li><a href="{% url 'news-year-archive' yearvar %}">{{ yearvar }} Archive</a></li>
{% endfor %}
</ul>

Или в коде Python:

from django.http import HttpResponseRedirect
from django.urls import reverse


def redirect_to_year(request):
    # ...
    year = 2006
    # ...
    return HttpResponseRedirect(reverse("news-year-archive", args=(year,)))

Если по какой-либо причине было решено изменить URL-адреса, по которым публикуются архивы статей на год, вам нужно будет изменить только запись в URLconf.

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

Именование URL-шаблонов

Для выполнения обратного поиска URL-адресов необходимо использовать именованные URL-шаблоны, как показано в примерах выше. Строка, используемая для имени URL, может содержать любые символы. Вы не ограничены только допустимыми именами Python.

При именовании шаблонов URL выбирайте имена, маловероятные для конфликтов с именами других приложений. Если вы назовете свой шаблон URL comment и другое приложение сделает то же самое, URL, который reverse() найдёт, зависит от того, какой шаблон находится последним в списке urlpatterns вашего проекта.

Добавление префикса к именам URL, возможно, полученного из имени приложения (например, myapp-comment вместо comment), уменьшает вероятность коллизий.

Вы можете намеренно выбрать то же имя URL, что и другое приложение, если хотите переопределить представление. Например, распространённый случай — переопределение LoginView. Части Django и большинство сторонних приложений предполагают, что это представление имеет шаблон URL с именем login. Если у вас есть пользовательское представление входа и вы дадите его URL имя login, reverse() найдет ваше пользовательское представление, пока оно находится в urlpatterns после включения django.contrib.auth.urls (если это включено вообще).

Вы также можете использовать одно и то же имя для нескольких шаблонов URL, если они отличаются своими аргументами. В дополнение к имени URL, reverse() сопоставляет количество аргументов и имена именованных аргументов. Конвертеры путей также могут генерировать ValueError для указания отсутствия совпадения, см. Регистрация пользовательских конвертеров путей для получения подробной информации.

Пространства имён URL

Введение

Пространства имён URL позволяют вам однозначно перенаправлять именованные шаблоны URL, даже если разные приложения используют одни и те же имена URL. Это хорошая практика для сторонних приложений всегда использовать пространственно-именованные URL (как мы сделали в учебнике). Аналогично, это также позволяет вам перенаправлять URL, если развернуты несколько экземпляров приложения. Другими словами, поскольку несколько экземпляров одного приложения будут использовать общие именованные URL, пространства имён предоставляют способ отличить эти именованные URL.

Приложения Django, которые надлежащим образом используют пространства имён URL, могут быть развернуты более одного раза для конкретного сайта. Например, django.contrib.admin имеет класс AdminSite, который позволяет вам развернуть более одного экземпляра админ-панели. В дальнейшем примере мы обсудим идею развертывания приложения опросов из учебника в двух разных местах, чтобы мы могли предоставлять одинаковую функциональность двум разным аудиториям (авторам и издателям).

Пространство имён URL состоит из двух частей, обе являются строками:

application namespace
Это описывает имя приложения, которое развертывается. Каждый экземпляр одного приложения будет иметь то же пространство имён приложения. Например, приложение администрирования Django имеет достаточно предсказуемое пространство имён приложения 'admin'.
instance namespace
Это идентифицирует конкретный экземпляр приложения. Пространства имён экземпляров должны быть уникальными во всём вашем проекте. Однако пространство имён экземпляра может быть таким же, как пространство имён приложения. Это используется для указания стандартного экземпляра приложения. Например, стандартный экземпляр администрирования Django имеет пространство имён экземпляра 'admin'.

Пространственно-именованные URL задаются с использованием оператора ':'. Например, главная страница индекса приложения администрирования ссылается на 'admin:index'. Это указывает на пространство имён 'admin', и именованный URL 'index'.

Пространства имён также могут быть вложенными. Имянованный URL 'sports:polls:index' искал бы шаблон с именем 'index' в пространстве имён 'polls', которое само определено в пространстве имён верхнего уровня 'sports'.

Перенаправление пространственно-именованных URL

При получении пространственно-именованного URL (например, 'polls:index') для разрешения, Django разбивает полное квалифицированное имя на части и затем выполняет поиск следующим образом:

  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() кортеж из 2 элементов, содержащий:

(<list of path()/re_path() instances>, <application namespace>)

Например:

from django.urls import include, path

from . import views

polls_patterns = (
    [
        path("", views.IndexView.as_view(), name="index"),
        path("<int:pk>/", views.DetailView.as_view(), name="detail"),
    ],
    "polls",
)

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

Это включит указанные шаблоны URL в заданное пространство имён приложения.

END_OF_DOCUMENT_MARKER

Пространство имен экземпляра можно указать, используя аргумент namespace к include(). Если пространство имен экземпляра не указано, оно будет по умолчанию соответствовать пространству имен приложения включенного URLconf. Это означает, что оно также будет экземпляром по умолчанию для этого пространства имен.

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

Spec-Zone.ru

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