Менеджер URL-ов¶
Чистая и элегантная схема URL-адресов — важная деталь высококачественного веб-приложения. Django позволяет создавать URL-адреса так, как вы хотите, без каких-либо ограничений платформы.
Читайте Cool URIs don’t change, создателя World Wide Web, Тима Бернерса-Ли, чтобы узнать почему URL-ы должны быть красивыми и практичными.
Обзор¶
Для определения URL-ов приложения, создайте модуль Python, неофициально названный URLconf (конфигурация URL-ов). Этот модуль содержит код Python, который отображает URL-шаблоны (регулярные выражения) и связанные функции Python (ваши представления).
Эта конфигурация может быть короткой или длинной настолько, насколько это нужно. Она может ссылаться на другие конфигурации. И, так как это код Python, может создаваться динамически.
Django также предоставляет метод для перевода URL на текущий язык. Обратитесь к документации на интернационализацию для подробностей.
Как Django обрабатывает запрос¶
При запросе к странице вашего Django-сайта, используется такой алгоритм для определения какой код выполнить:
Django определяет какой корневой модуль URLconf использовать. Обычно, это значение настройки
ROOT_URLCONF, но, если объект запросаHttpRequestсодержит атрибутurlconf(установленный request middleware), его значение будет использоваться вместоROOT_URLCONF.Django загружает модуль конфигурации URL и ищет переменную
urlpatterns. Это должен быть список экземпляровdjango.conf.urls.url().Django перебирает каждый URL-шаблон по порядку, и останавливается при первом совпадении с запрошенным URL-ом.
Если одно из регулярных выражений соответствует URL-у, Django импортирует и вызывает соответствующее представление, которое является просто функцией Python(или представление-класс). При вызове передаются следующие аргументы:
Объект
HttpRequest.Если в результате применения регулярного выражения получили именованные совпадения, они будут переданы как позиционные аргументы.
Именованные аргументы создаются из именованных совпадений. Они могут быть перезаписаны значениями из аргумента
kwargs, переданного вdjango.conf.urls.url().Changed in Django 3.0:In older versions, the keyword arguments with
Nonevalues are made up also for not provided named parts.
Если ни одно регулярное выражение не соответствует, или возникла ошибка на любом из этапов, Django вызывает соответствующий обработчик ошибок. Смотрите Error handling ниже.
Примеры¶
Вот пример простого 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, '2005', '03')./articles/2003/соответствует первому выражению, не второму, потому что шаблоны проверяются по порядку и берется первый найденный. Не стесняйтесь использовать порядок для обработки различных ситуаций, таких как эта. В данном примере Django вызовет функциюviews.special_case_2003(request)./articles/2003не соответствует ни одному регулярному выражению, потому что каждое ожидает, что URL оканчивается на косую черту./articles/2003/03/03/соответствует последнему выражению. Django вызовет функциюviews.article_detail(request, '2003', '03', '03').
Преобразователи пути¶
По умолчанию доступны следующие преобразователи путей:
str— соответствует любой непустой строке, за исключением разделителя пути'/'. Это значение по умолчанию, если преобразователь не включен в выражение.int— соответствует нулю или любому положительному целому числу. Возвращаетint.slug— соответствует любой короткой строке, состоящей из букв или цифр ASCII, а также символов дефиса и подчеркивания. Например,создайте свой первый сайт на Django.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.Changed in Django 3.1:Support for raising
ValueErrorto indicate no match was added.
Например:
class FourDigitYearConverter:
regex = '[0-9]{4}'
def to_python(self, value):
return int(value)
def to_url(self, value):
return '%04d' % value
Зарегистрируйте пользовательские классы конвертеров в вашей конфигурации URL, используя 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 – шаблон.
Вот пример конфигурации URL, переписанный с использованием именованных групп:
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 больше не будет соответствовать, поскольку целые числа года ограничены длиной ровно четыре цифры.
Каждый найденный аргумент передается в представление как строка, независимо от того, какое «совпадение» определено в регулярном выражении. Например, URLconf содержит такую строку:
При переключении с использования 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
]
Оба шаблона используют вложенные аргументы и могут обрабатывать URL-ы: например, для blog/page-2/ будет найдено представление blog_articles с двумя позиционными аргументами page-2/ и 2. Второй URL-шаблон для comments для comments/page-2/ найдет именованный аргумент page_number со значеним 2. Внешний аргумент в этом случае не захватываемый из-за (?:...).
При получении URL-а для представления blog_articles необходимо указать самый внешний аргумент(page-2/) или ни одного аргумента в данном случае. В то время как для comments необходимо передать значение page_number или не одного аргумента.
Вложенные захватываемые аргументы создают сильную связанность между URL и аргументами представления, как это показано для blog_articles: представление получает часть URL-а (page-2/) вместо значение, которое на самом деле необходимо представлению. Эта связанность особенно заметна при создании URL-а т.к. необходимо передать часть URL-а вместо номера страницы.
Как правило, URL-шаблон должен захватывать только необходимые для представления аргументы.
Что использует URLconf при поиске нужного шаблона URL¶
URLconf использует запрашиваемый URL как обычную строку Python. Он не учитывает параметры GET, POST и имя домена.
Например, при запросе к https://www.example.com/myapp/, URLconf возьмет myapp/.
При запросе к https://www.example.com/myapp/?page=3 – 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 из URL, которое найдет регулярное выражение.
Производительность¶
Each regular expression in a urlpatterns is compiled the first time it’s
accessed. This makes the system blazingly fast.
Синтаксис переменной urlpatterns¶
urlpatterns должен быть списком экземпляров url().
Обработчики ошибок¶
Если Django не может найти подходящий шаблон URL, или было вызвано исключение в процессе обработки запроса, Django вызовет соответствующее представление обрабатывающее ошибку.
Эти представления определены в четырёх переменных. Их значения по-умолчанию должны подойти для большинства проектов, но вы можете их поменять при необходимости.
Подробности в разделе о переопределении обработчика ошибок.
Эти значения должны быть определены в главном URLconf.
Значение это функции, или полный путь для импорта, которая будет вызвана, если не был найден подходящий URL-шаблон.
Есть следующие переменные:
handler400– Смотритеdjango.conf.urls.handler400.handler403– Смотритеdjango.conf.urls.handler403.handler404– Смотритеdjango.conf.urls.handler404.handler500– Смотритеdjango.conf.urls.handler500.
Комбинирование URLconfs¶
В любой момент, ваш urlpatterns может «включать» другие модули URLconf.
Вот пример URLconf для сайта Django. Он включает множество других конфигураций URL:
from django.urls import include, path
urlpatterns = [
# ... snip ...
path('community/', include('aggregator.urls')),
path('contact/', include('contact.urls')),
# ... snip ...
]
Заметим, что регулярные выражения не содержат $ (определитель конца строки), но содержит косую черту в конце. Каждый раз, когда Django встречает include() (django.conf.urls.include()), из URL обрезается уже совпавшая часть, остальное передается во включенный URLconf для дальнейшей обработки.
Другой возможностью будет добавление дополнительных URL-шаблонов с помощью списка экземпляров 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/ обработан представлением 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¶
Включенный URLconf получает все аргументы найденные родительским URLconfs, поэтому этот пример работает:
# 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, как и ожидалось.
Передача дополнительных аргументов в представление¶
Конфигурация URL-ов позволяет определить дополнительные аргументы для функции представления, используя словарь Python.
Функция django.conf.urls.url() может принимать третий необязательный элемент. Этот элемент является словарем, который определяет дополнительные именованные аргументы для функции представления.
Например:
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').
Такой подход используется в syndication framework для передачи параметров и дополнительных данных в представление.
Конфликты переменных
Если регулярное выражение URL-шаблона выделяет из URL-а аргумент с названием, которое уже используется в дополнительных именованных аргументах, будет использован аргумент из словаря дополнительных аргументов, вместо значения из URL.
Передача дополнительных аргументов в include()¶
Аналогично вы можете передать дополнительные аргументы в include(). При этом, каждый URL-шаблон включенного 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, независимо от того, принимает оно эти аргументы или нет. Поэтому, такой подход полезен только если вы уверенны, что каждое представление принимает передаваемые аргументы.
Поиск URL-а по URL-шаблону¶
Обычной задачей является получение URL-а по его определению для отображения пользователю или для редиректа.
Очень важно не «хардкодить» URL-ы (трудоемкая и плохо поддерживаемая стратегия). Также не следует создавать «костыли» для генерации URL-ов, которые не следуют задокументированному дизайну URLconf.
В общем необходимо придерживаться принципа DRY. Немаловажно иметь возможность менять URL-ы в одном месте, а не выполнять поиск и замену по всему проекту.
Для получения URL-а нам необходим его идентификатор, то есть название URL-шаблона, и позиционные и именованные аргументы.
В Django для работы с URL-ами используется так называемый «URL mapper». Ему передается URLconf, и теперь его можно использовать в два направления:
Получая запрошенный URL находит необходимое представление и предоставляет все необходимые аргументы полученные из URL-а.
Получая идентификатор представления и передаваемые ему аргументы, возвращает URL.
Первое это то, что мы уже рассмотрели в предыдущем разделе. Второе называется URL reversing, в общем получение URL-а по его названию.
Django предоставляет инструменты для получения URL-ов в различных компонентах фреймворка:
В шаблонах: Использование шаблонного тега
url.В Python коде: Использование функции
django.core.urlresolvers.reverse().На более высоком уровне для привязки URL-ов к моделям - метод
get_absolute_url().
Примеры¶
Рассмотрим следующий URLconf:
from django.urls import path
from . import views
urlpatterns = [
#...
path('articles/<int:year>/', views.year_archive, name='news-year-archive'),
#...
]
В соответствии с ним архиву nnnn года соответствует URL /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. Как решить эту проблему читайте в следующем разделе.
Именованные URL-шаблоны¶
Для того, чтобы выполнить обратное разрешение URL, вам потребуется использовать именованные URL шаблоны, как это показано в примерах выше. Строка, использованная для наименования URL, может содержать любые символы. Вы не ограничены только теми именами, что позволяет Python.
При выборе названия для URL-шаблона, убедитесь что оно достаточно уникально. Если вы назовете URL-шаблон comment, и другое приложение сделает аналогичное, нет гарантии что в шаблон будет вставлен правильный URL.
Добавление префикса к названию URL-шаблона, возможного состоящего из названия приложения, уменьшит шанс конфликта. Мы советуем использовать myapp-comment вместо comment.
Вы можете сознательно выбрать то же имя URL, что и у другого приложения, если хотите переопределить представление. Например, общий вариант использования — переопределить LoginView. Части Django и большинство сторонних приложений предполагают, что это представление имеет шаблон URL-адреса с именем «login». Если у вас есть собственное представление входа в систему и вы дали его URL-адресу имя login, reverse() найдет ваше пользовательское представление, если оно находится в urlpatterns после включения django.contrib.auth.urls (если оно вообще включено).
Вы также можете использовать одно и то же имя для нескольких шаблонов URL-адресов, если они различаются своими аргументами. Помимо имени URL, reverse() соответствует количеству аргументов и именам аргументов ключевого слова. Преобразователи путей также могут выдавать ValueError, чтобы указать на отсутствие совпадения, подробности см. в разделе «registering-custom-path-converters».
Пространства имен в конфигурации URL-ов¶
Описание¶
Пространства имен позволяют получить URL по названию URL-шаблона даже, если несколько приложений используют одинаковые названия. Для сторонних приложений использование пространств имен – хорошая практика (как мы и делали в учебнике). Аналогично можно получить URL, если несколько экземпляров одного приложения подключены в конфигурацию URL-ов.
Django приложения, правильно используя пространство имен для URL, могут использоваться в нескольких экземплярах на проекте. Например, django.contrib.admin содержит класс AdminSite, который легко позволяет подключить несколько интерфейсов администратора. Ниже мы опишем как сделать аналогично для нашего приложения опросов, чтобы можно было создать несколько интерфейсов (для авторов и издателей).
Пространство имен состоит из двух частей, каждая из которых это строка:
- application namespace¶
Указывает название установленного приложения. Все экземпляры одного приложения будет иметь одно название. Например, название приложения администратора Django –
admin.- instance namespace¶
Идентифицирует конкретный экземпляр приложения. Должно быть уникальным для проекта. Однако, название экземпляра может быть равным названию приложения. Оно используется по-умолчанию при создании приложения. Например, пространство имен приложения администратора Django –
admin.
Пространство имен определяется с помощью оператора ':'. Например, главная страница интерфейса администратора определяется как 'admin:index'. Мы видим пространство имен 'admin', и название URL-шаблона 'index'.
Пространства имен могут быть вложенными. Название URL-а 'sports:polls:index' означает именованный URL-шаблон с названием 'index' в пространстве имен 'polls', которое было определенно в другом пространстве имен - 'sports'.
Поиск URL-а по шаблону с пространством имен¶
Если необходимо найти URL по названию с пространством имен (например, 'polls:index'), Django разбивает название на части и следует такому алгоритму:
Первым делом, Django проверяет название(пространсву имен) приложения (например,
polls). Django получает список экземпляров приложения.Если указан текущий экземпляр приложения, Django найдёт и вернет «URL resolver» для этого экземпляра. Текущее приложение можно указать с помощью аргумента
current_appфункцииreverse().Шаблонный тег
urlиспользует пространство имен представления как текущее приложение вRequestContext. Вы можете переопределить его, указав в атрибутеrequest.current_app.Если текущий экземпляр приложения не найден, Django попытается использовать экземпляр по-умолчанию. Экземпляр по-умолчанию – это экземпляр, у которого instance namespace и application namespace совпадают (в нашем примере это экземпляр
pollsс названиемpolls).Если экземпляр по-умолчанию не найден, Django возьмет последний установленный экземпляр приложения, не обращая внимание на его название.
Если на первом шаге не было найдено приложение по указанному пространству имен, Django попытается найти экземпляр приложения по его названию, используя пространство имен как название экземпляра.
Если пространство имен вложенное, этот процесс будет повторен, пока неопределенным не останется только название представления. URL для названия представления будет искаться среди URL-шаблонов определенных в приложении, найденном через пространство имен.
Примеры¶
Разберем небольшой пример. У нас есть два экземпляра приложения polls: один назван 'author-polls', другой - 'publisher-polls'. Предположим, что мы уже изменили код приложения и оно учитывает текущее пространство имен при создании страниц.
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')),
]
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'),
...
]
Для таких настроек URL-ов возможны следующие варианты поиска URL-а по названию:
Если один из экземпляров указан как текущий - например, мы выполняем шаблон в экземпляре
'author-polls'- поиск URL-а по'polls:index'вернет URL на главную страницу экземпляра приложения'author-polls'. То есть мы получим"/author-polls/"для двух, приведенных ниже, примеров.В методе представления:
reverse('polls:index', current_app=self.request.resolver_match.namespace)
и в шаблоне:
{% url 'polls:index' %}
Если текущий экземпляр приложения не указан - например, мы ищем URL в другом приложении - поиск по
'polls:index'вернет URL для последнего добавленного экземпляра'polls'. Т.к. у нас не определен экземпляр приложения по умолчанию (с instance namespace равным'polls'), будет использоваться последний добавленный экземплярpolls. Это будет'publisher-polls'т.к. он последний вurlpatterns.Поиск по
'author-polls:index'всегда вернет ссылку на главную страницу экземпляра приложения'author-polls'(аналогично и для'publisher-polls').
Если бы у нас был экземпляр приложения по умолчанию – то есть с instance name 'polls' – у нас бы поменялся результат только для тех случаев, где не указан текущий экземпляр (второй пункт в списке выше). В этом случае для 'polls:index' мы бы получили ссылку на главную страницу экземпляра приложения по умолчанию, а не для последнего в urlpatterns.
Пространства имен в URL -ах и include¶
Название приложения в URLconfs можно определить двумя путями.
Первый – вы можете указать атрибут app_name в модуле URLconf приложения, на том же уровне, что и атрибут urlpatterns. При этом вам необходимо передать сам модуль, или путь к импорту модуля, в функцию include(), а не список urlpatterns.
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'),
...
]
from django.urls import include, path
urlpatterns = [
path('polls/', include('polls.urls')),
]
URL-ы, определенные в polls.urls, содержат название приложения polls.
Secondly, you can include an object that contains embedded namespace data. If
you include() a list of path() or
re_path() instances, the URLs contained in that object
will be added to the global namespace. However, you can also include() a
2-tuple containing:
(<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(). Если он не указан, будет использовать название приложения.