Программа курса:
Диспетчер URL
Чистая, элегантная схема URL-адресов — важная деталь в высококачественном веб-приложении. Django позволяет создавать URL-адреса так, как вы хотите, без ограничений фреймворка.
В прошлом разделе мы рассмотрели, как запрос браузера пользователя передается из его браузера на «входную дверь» Django. Теперь пришло время посмотреть, как Django обрабатывает эти запросы.
HTTP-запрос от браузера включает URL-адрес, описывающий, какой ресурс должен создавать Django.
Поскольку URL-адреса могут принимать разные формы, нам нужно сообщить Django о типах URL-адресов, которые может обрабатывать наше веб-приложение. Вот для чего нужны настройки URL.
В документации Django конфигурация URL для краткости называется URLconf
.
URLconf в действии
Попробуйте представить конфигурацию URL-адресов как список путей URL-адресов, которые Django будет пытаться сопоставить сверху вниз.
Когда Django находит соответствующий маршрут, HTTP-запрос направляется во фрагмент кода Python, связанный с этим маршрутом. Этот «кусок кода Python» называется представлением, которое мы объясним подробнее чуть позже.
Изменим в файле views.py
приложения blog
код на следующий:
from django.http import HttpResponse
def index(request):
return HttpResponse('<h2>Главная</h2>')
def about(request):
return HttpResponse('<h2>О сайте</h2>')
def contact(request):
return HttpResponse('<h2>Контакты</h2>')
И в файле urls.py
приложения (blog/urls.py
) мы можем сопоставить их с адресами URL с помощью функции path()
:
from django.urls import path
from blog import views
urlpatterns = [
path('', views.index),
path('about/', views.about),
path('contact/', views.contact),
]
Функция path()
в Django используется для определения URL-маршрутов в файлах urls.py
.
path(route, view, kwargs=None, name=None)
Она имеет несколько параметров:
route
(обязательный): Строка, представляющая шаблон URL. Она может содержать статические части и параметры (placeholders).- Статические части: Текст, который должен точно совпадать с URL-адресом. Например,
/about/
,/contact/
. - Параметры (placeholders): Части URL-адреса, которые могут меняться. Они заключаются в угловые скобки
< >
, где первым указывается конвертер, а через символ двоеточия указывается имя параметра, например:<int:id>
,<str:slug>
.<int:name>
: Ожидает целое число. Значение будет доступно в представлении как аргумент с именемname
.<str:name>
: Ожидает строку. Значение будет доступно в представлении как аргумент с именемname
.<path:name>
: Ожидает любую строку (включая слеши). Значение будет доступно в представлении как аргумент с именемname
.<slug:name>
: Ожидает URL-slug (строку, состоящую из букв, цифр, тире и подчеркиваний). Значение будет доступно в представлении как аргумент с именемname
.<uuid:name>
: Ожидает UUID. Значение будет доступно в представлении как аргумент с именемname
.
- Статические части: Текст, который должен точно совпадать с URL-адресом. Например,
view
(обязательный): Вызываемый (callable) объект, чаще всего функция-представление (view function), которая будет обрабатывать запросы, соответствующие этому URL-маршруту.kwargs
(необязательный): Словарь, который передается в представление в качестве дополнительных аргументов. Это позволяет передавать контекстные данные в представление без необходимости изменять сигнатуру функции.name
(необязательный): Строка, которая дает имя URL-маршруту. Именованные URL-адреса полезны для создания ссылок в шаблонах и для обратной связи (reverse URL resolution).
В примере выше мы использовали только обязательные параметры: шаблон URL-адреса и имя функции, которая будет обрабатывать запрос по этому адресу.
Так-же мы можем указать имя маршрута через третий параметр:
path('', views.index, name='home'),
В этом примере мы указали имя home
для маршрута.
Мы можем проработать пример, чтобы увидеть, как это работает для example.com
. При рассмотрении URL-адреса в URLconf
Django игнорирует схему https://
, домен example.com
и начальную косую черту(/) для сопоставления. Все остальное — это то, с чем будет сравниваться URLconf.
- Запрос к
https://example.com/about/
будет выглядеть как'about/'
в процессе сопоставления с шаблоном и будет соответствовать второму маршруту. Этот запрос направляется в представлениеviews.about
. - Запрос к
https://example.com/
будет рассматриваться как''
(пустая строка) в процессе сопоставления с шаблоном и будет соответствовать первому маршруту. Этот запрос направляется в представлениеviews.index
.
Порядок в этом списке также важен, потому что Django прекратит сканирование списка, как только найдет совпадение. В примере не показаны какие-либо конфликты между маршрутами, но можно создать две разные path
записи маршрута, они могут соответствовать одному и тому же URL-адресу, который отправляет пользователь. Я покажу пример того, как это может произойти, после того как мы рассмотрим другой аспект маршрутов.
В качестве отступления: вы можете заметить, что URL-адреса Django заканчиваются символом косой черты. Такое поведение обусловлено выбором Django. На самом деле, если вы попытаетесь перейти по URL-адресу, например
https://example.com/about
, Django перенаправит запрос на тот же URL-адрес с добавленной косой чертой в конце из-за конфигурацииAPPEND_SLASH=True
.
Давайте запустим сервер и попробуем перейти по страницам. По адресу мы видим вывод функции index
:
По адресу мы видим вывод функции about
А по адресу мы видим вывод функции contact
re_path
Функция re_path()
в Django (теперь устаревшая, рекомендуется использовать path()
с регулярными выражениями внутри) позволяла определить URL-паттерны с использованием регулярных выражений. Хотя re_path()
фактически устарела в пользу path()
с использованием re.compile()
для более сложных паттернов, понимание ее параметров все еще полезно для работы со старым кодом.
re_path(route, view, kwargs=None, name=None)
Она имеет такие же параметры как и у функции path()
:
route
(обязательный): Строка, содержащая регулярное выражение для сопоставления URL-адреса. В отличие отpath()
, здесь нет встроенной поддержки именованных параметров. Для определения параметров в регулярном выражении используются именованные группы(?P<name>pattern)
.view
(обязательный): Вызываемый объект (callable), обычно функция-представление (view function), которая будет обрабатывать запросы, соответствующие этому URL-маршруту.kwargs
(необязательный): Словарь, который передается в представление в качестве дополнительных аргументов.name
(необязательный): Строка, дающая имя URL-маршруту. Полезно для создания ссылок в шаблонах и для обратной связи (reverse URL resolution).
Преимущество использования функции re_path()
состоит в том, что она позволяет задать шаблоны URL-адресов с помощью регулярных выражений.
Например, если мы изменим содержимое файла urls.py
следующим образом:
from django.urls import path, re_path
from blog import views
urlpatterns = [
path('', views.index),
re_path(r'^about/', views.about),
re_path(r'^contact/', views.contact),
]
Первый маршрут мы не меняли, он сделан на основе функции path()
и обрабатывает запросы в корневую директорию приложения.
Два других маршрута сделаны с использованием функции re_path()
. Но так как мы используем регулярное выражение в качестве шаблона пути, то перед его строкой ставится буква r
.
В шаблоне адреса можно применять разные элементы синтаксиса регулярных выражений. Например, с помощью выражения r'^about/'
задаётся условие, что адрес должен начинаться на about/
. Но это не обязательно должна быть точная строка about/
, как в случае с функцией path()
.
Можно обратиться к любому адресу, который начинается на about/
, и такой запрос будет обработан функцией views.about
.
Даже запрос по адресу приведёт к выполнению представления views.about
.
Очередность маршрутов
Порядок маршрутов в списке urlpatterns
имеет значение. Django обрабатывает URL-паттерны сверху вниз, поэтому важно разместить более специфичные URL-паттерны (с большим количеством параметров) выше более общих.
Понимание этих параметров позволяет создавать гибкие и структурированные URLconf, что критически важно для масштабируемых и поддерживаемых веб-приложений Django.
Например:
from django.urls import path, re_path
from blog import views
urlpatterns = [
re_path(r'^about/contact/', views.contact),
re_path(r'^about/', views.about),
path('', views.index),
]
В данном случае адрес ^about/contact/
представляет более конкретный маршрут по сравнению c ^about/
. Поэтому он определяется в первую очередь.
Если бы было наоборот:
urlpatterns = [
path('', views.index),
re_path(r'^about/', views.about),
re_path(r'^about/contact/', views.contact),
]
то запрос по адресу ^about/contact/
обрабатывался бы функцией views.about
.