Django 5 для начинающих

Прогресс по курсу:  9/1004

2.4 Диспетчер URL, часть 1.
4 из 14 шагов пройдено
0 из 42 баллов  получено

Чистая, элегантная схема 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)
  1. route: представляет шаблон адреса URL, которому должен соответствовать запрос

  2. view: функция-представление, которое обрабатывает запрос

  3. kwargs: дополнительные аргументы, которые передаются в функцию-представление

  4. 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.


  • Комментариев
Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Оставить комментарий
Комментарий закреплён

Понравилась задача, тест или урок? Поставьте лайк, поддержите курс. Ваша поддержка очень важна для нас.

Если в файле urls.py приложения (blog/urls.py) при первом импорте

 

PyCharm выдает ошибку Unresolved reference (Неразрешенная ссылка) и подчеркивает красным:

То нужно указать наш проект как основной рабочий каталог -> нажмите ПКМ по названию проекта, далее по скрину:

Выберете: Mark Directory as -> Sources Root (Пометить каталог как -> Корневой источник)

@Максим_Михеев, можно blog заменить на точку (.), все также будет работать 

Дмитрий, если использовать файл одного приложения в другом, то << . >> не обойтись, а PyCharm будет подчёркивать ошибку
Хорошо, что автор рассказывает про подобные практики и правила парсинга Django списка URL-ов, в других курсах подобного не встречал

Предназначение параметра name в функциях path и re_path из django.urls (ответ нейросети):

from django.urls import path

urlpatterns = [
    path('articles/', views.article_list, name='article-list'),
    ...
]


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

<a href="{% url 'article-list' %}">Список статей</a>

Здесь {% url 'article-list' %} используется для создания URL-адреса на основе имени маршрута 'article-list'

Преимущества использования имен маршрутов:

  • Удобство и читаемость: Использование имен маршрутов делает ваш код более читаемым и удобным для понимания.
  • Гибкость при изменении URL: Если вам нужно изменить URL-адрес маршрута, вы можете сделать это только в одном месте - в определении маршрута. Все ссылки на этот маршрут будут автоматически обновлены.

Таким образом, параметр name в функциях path() и re_path() в Django позволяет задать идентификатор для маршрута, что упрощает его ссылку из других частей вашего приложения и делает ваш код более читаемым и гибким.

@Нарбеков_Марсель, Мы дальше на практике будем использовать параметр name, и все станет понятно. В вводных лекциях о маршрутах не стали на этом заострять внимание.

Например, мы можем обратиться по любому адресу, главное чтобы он начинался с about, и тогда подобный запрос будет обрабатываться функцией views.about. Причем даже запрос http://127.0.0.1:8000/about/hello отправит запрос в представление views.about.

А в чем практический смысл такой логики? Может есть более практичный пример, т.к. пока выглядит странным такое поведение, и вроде нигде такого не встречал, или не просто замечал...

@Нарбеков_Марсель, Тут логика немного в другом, если в случае в path() когда мы указываем как path('about/', views.about), то представление отработает только у маршрута http://127.0.0.1:8000/about/, а маршрут http://127.0.0.1:8000/about/test/ выдаст 404 ошибку.

То у re_path() все иначе, тут уже работают регулярные выражения, в случае re_path("about/", views.about), при переходе на http://127.0.0.1:8000/about/, так и http://127.0.0.1:8000/about/test/, а также и http://127.0.0.1:8000/test/about/, все будет обработано представлением. И в данном случае, чтобы получить ту же логику как и у path(), нам нужно закрывать строку регулярных выражений символом $ - re_path("about/$", views.about)

На практике можно использовать например для обработки подобных урлов:

 

/product/comment
/company/comment
/seller/comment

Где будет одно представление отвечать за вывод комментариев.

@Илья_Перминов, Спасибо, вроде даже почти понял, но может у вас есть более конкретный пример практического использования, подойдет любой пример (наверное тяжело/невозможно узнать на чем был реализован тот или иной сайт), где логика реализована похожим образом?

@Нарбеков_Марсель, тут больше возможности re_path показаны, как можно обработать группу адресов(основную директорию и поддиректории в ней) в одном представлении. Сайт с практическим примером не подскажу, потому, что даже если 100% знать что сайт работает на Django, то это никак не поможет определить как реализованы маршруты и представления у него.

@Дмитрий_Селезнев, Понял, спасибо!