Программа курса:
Диспетчер 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.