Чистая, элегантная схема 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.urls и она принимает четыре параметра:
path(route, view, kwargs=None, name=None)
-
route: представляет шаблон адреса URL, которому должен соответствовать запрос -
view: функция-представление, которое обрабатывает запрос -
kwargs: дополнительные аргументы, которые передаются в функцию-представление -
name: название маршрута
В примере выше применялись только первые два параметра, они являются обязательными: запрошенный адрес URL и функция, которая обрабатывает запрос по этому адресу. Дополнительно через третий параметр можно указать имя маршрута:
path('', views.index, name='home'),
В данном случае маршрут будет называться home.
Мы можем проработать пример, чтобы увидеть, как это работает для www.example.com. При рассмотрении URL-адреса в URLconf Django игнорирует схему https://, домен www.example.com и начальную косую черту для сопоставления. Все остальное — это то, с чем будет сравниваться URLconf.
-
Запрос к
https://www.example.com/about/будет выглядеть какabout/процесс сопоставления с шаблоном и будет соответствовать второму маршруту. Этот запрос направляется в представлениеviews.about. -
Запрос к
https://www.example.com/будет рассматриваться как""(пустая строка) в процессе сопоставления с шаблоном и будет соответствовать первому маршруту. Этот запрос направляется в представлениеviews.index.
Порядок в этом списке также важен, потому что Django прекратит сканирование списка, как только найдет совпадение. В примере не показаны какие-либо конфликты между маршрутами, но можно создать две разные path записи маршрута, они могут соответствовать одному и тому же URL-адресу, который отправляет пользователь. Я покажу пример того, как это может произойти, после того как мы рассмотрим другой аспект маршрутов.
В качестве отступления: вы можете заметить, что URL-адреса Django заканчиваются символом косой черты. Такое поведение обусловлено выбором философии дизайна Django. На самом деле, если вы попытаетесь перейти по URL-адресу, например
https://www.example.com/about, Django перенаправит запрос на тот же URL-адрес с добавленной косой чертой в конце из-за конфигурации по умолчаниюAPPEND_SLASH.
Давайте запустим сервер и попробуем перейти по страницам. По адресу http://127.0.0.1:8000/ мы видим вывод функции index
По адресу http://127.0.0.1:8000/about/ мы видим вывод функции about
А по адресу http://127.0.0.1:8000/contact/ мы видим вывод функции contact
re_path
Хотя мы можем успешно применять функцию path() для определения маршрутов, она довольно ограничена по своему действию:
Запрошенный путь должен в точности соответствовать указанному в маршруте адресу URL. Так, в примере выше чтобы функция views.about могла обрабатывать запрос, адрес должен быть в точности about/. Например, стоит нам убрать слеш в конце: about и django уже не сможет сопоставить путь с запросом.
В качестве альтернативы для определения маршрутов мы можем использовать функцию re_path(), которая также располагается в пакете django.urls и имеет тот же набор параметров:
re_path(route, view, kwargs=None, name=None)
Ее преимущество состоит в том, что она позволяет задать адреса 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(). Причем, поскольку определяется регулярное выражение, то перед строкой с шаблоном адреса URL ставится буква r.
В самом шаблоне адреса можно использовать различные элементы синтаксиса регулярных выражений. В частности, выражение ^about указывает, что адрес должен начинаться с about. Однако он необязательно в точности должен соответствовать строке about, как это было в случае с функцией path.
Например, мы можем обратиться по любому адресу, главное чтобы он начинался с about, и тогда подобный запрос будет обрабатываться функцией views.about. Причем даже запрос http://127.0.0.1:8000/about/hello отправит запрос в представление views.about.
Очередность маршрутов
Когда запрос приходит к приложению, то система проверяет соответствие запроса маршрутам по мере их определения: вначале сравнивается первый маршрут, если он не подходит, то сравнивается второй и так далее.
Поэтому более общие маршруты должны определяться в последнюю очередь, а более конкретные маршруты должны идти в начале. Например:
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.