Spec-Zone.ru › Django 2.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.
  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.
  • Метод to_url(self, value), который обрабатывает преобразование типа Python в строку для использования в URL.

Например:

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

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

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

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

from django.urls import path, register_converter

from . import converters, views

register_converter(converters.FourDigitYearConverter, 'yyyy')

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

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

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

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

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

from django.urls import path, re_path

from . import views

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

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

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

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

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

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

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

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

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

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

from django.urls import re_path

urlpatterns = [
    re_path(r'^blog/(page-(\d+)/)?$', blog_articles),                  # bad
    re_path(r'^comments/(?:page-(?P<page_number>\d+)/)?$', comments),  # good
]

Оба шаблона используют вложенные аргументы и будут разрешены: например, blog/page-2/ приведет к соответствию blog_articles с двумя позиционными аргументами: page-2/ и 2. Второй шаблон для comments будет соответствовать comments/page-2/ с ключевым аргументом page_number, установленным в 2. Внешний аргумент в этом случае — не захватывающий аргумент (?:...).

Представление blog_articles нуждается во внешнем захваченном аргументе для обратного преобразования, page-2/ или в этом случае без аргументов, в то время как comments может быть обращено с помощью либо без аргументов, либо с значением для page_number.

Вложенные захваченные аргументы создают сильную связь между аргументами представления и URL, как показано в blog_articles: представление получает часть URL (page-2/ ) вместо только значения, которое интересует представление. Эта связь еще более выражена при обратном преобразовании, так как для обратного преобразования представления нам нужно передать часть URL, а не только номер страницы.

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

Что ищет URLconf

Конфигурация URL обращается к запрошенному URL-адресу в качестве обычной строки Python. Это не включает параметры GET или POST, а также доменное имя.

Например, в запросе к https://www.example.com/myapp/, конфигурация URL будет искать myapp/.

В запросе к https://www.example.com/myapp/?page=3, конфигурация URL будет искать myapp/.

Конфигурация URL не учитывает метод запроса. Другими словами, все методы запроса – POST, GET, HEAD, и т. д. – будут маршрутизированы к одной и той же функции для одного и того же URL-адреса.

Указание значений по умолчанию для аргументов представления

Удобный трюк – указание значений по умолчанию для аргументов ваших представлений. Вот пример конфигурации URL и представления:

# 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, извлеченное из URL.

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

Каждый регулярное выражение в конфигурации URL компилируется при первом обращении к нему. Это делает систему невероятно быстрой.

Синтаксис переменной urlpatterns

urlpatterns должна быть последовательностью экземпляров path() и/или re_path().

Обработка ошибок

Когда Django не находит соответствия для запрошенного URL-адреса или возникает исключение, Django вызывает представление для обработки ошибок.

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

Полные сведения см. в документации по настройке представлений ошибок.

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

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

Переменные:

  • handler400 – См. django.conf.urls.handler400.
  • handler403 – См. django.conf.urls.handler403.
  • handler404 – См. django.conf.urls.handler404.
  • handler500 – См. django.conf.urls.handler500.

Включение других конфигураций URL

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

Например, вот фрагмент конфигурации URL для самого сайта Django. Он включает несколько других конфигураций URL:

from django.urls import include, path

urlpatterns = [
    # ... snip ...
    path('community/', include('aggregator.urls')),
    path('contact/', include('contact.urls')),
    # ... snip ...
]

Всякий раз, когда Django сталкивается с include(), он обрезает ту часть URL, которая соответствовала этому моменту, и отправляет оставшуюся строку в включенную конфигурацию URL для дальнейшей обработки.

Другой вариант – включить дополнительные шаблоны URL, используя список экземпляров path(). Например, рассмотрим эту конфигурацию URL:

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().

Это можно использовать для устранения избыточности в конфигурациях URL, где один префикс пути используется многократно. Например, рассмотрим эту конфигурацию URL:

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),
    ])),
]

Переменные, извлеченные из URL

Включенная конфигурация URL получает любые переменные, извлеченные из родительских конфигураций URL, поэтому следующий пример допустим:

# 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" передается включенной конфигурации URL, как ожидалось.

Передача дополнительных параметров функциям представления

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

Например, эти два набора конфигураций URL функционально идентичны:

Набор один:

# 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}),
]

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

Обратное разрешение URL-адресов

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

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

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

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

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

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

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

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

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

Примеры

Рассмотрим снова запись конфигурации URL:

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

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

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

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

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

polls/urls.py
from django.urls import path

from . import views

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

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

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-шаблоны в указанное пространство имён приложения.

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

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

Spec-Zone.ru

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