HTML Diff
0 added 0 removed
Original 2026-01-01
Modified 2026-02-26
1 <p>Важнейшей частью любого веб-фреймворка является механизм, который отвечает за маршрутизацию. Во Flask для построения карты маршрутов использовались специальные декораторы. В Django для этого используется свой небольшой<a>eDSL</a>. Он описывает<strong>urlpatterns</strong>- набор образцов, с которыми сопоставляются пути из каждого входящего запроса.</p>
1 <p>Важнейшей частью любого веб-фреймворка является механизм, который отвечает за маршрутизацию. Во Flask для построения карты маршрутов использовались специальные декораторы. В Django для этого используется свой небольшой<a>eDSL</a>. Он описывает<strong>urlpatterns</strong>- набор образцов, с которыми сопоставляются пути из каждого входящего запроса.</p>
2 <p>Каждый образец состоит из описания статических и динамических частей пути в виде строки или регулярного выражения:</p>
2 <p>Каждый образец состоит из описания статических и динамических частей пути в виде строки или регулярного выражения:</p>
3 <ul><li>Статические части пути в образце просто проверяются на равенство соответствующим участкам пути в запросе</li>
3 <ul><li>Статические части пути в образце просто проверяются на равенство соответствующим участкам пути в запросе</li>
4 <li>Динамические участки пути позволяют захватывать значения и передавать во view в качестве аргументов</li>
4 <li>Динамические участки пути позволяют захватывать значения и передавать во view в качестве аргументов</li>
5 </ul><p>Как только выясняется, что путь или его начало совпали с образцом, происходит либо вызов view, либо передача оставшейся части пути во вложенный блок<em>urlpatterns</em>. В большинстве больших Django-проектов<em>urlpatterns</em>вложены друг в друга и представляют собой дерево.</p>
5 </ul><p>Как только выясняется, что путь или его начало совпали с образцом, происходит либо вызов view, либо передача оставшейся части пути во вложенный блок<em>urlpatterns</em>. В большинстве больших Django-проектов<em>urlpatterns</em>вложены друг в друга и представляют собой дерево.</p>
6 <p>В этом уроке подробно разберем статические и динамические маршруты, а также рассмотрим вложенные<em>urlpatterns</em>и обратные маршруты.</p>
6 <p>В этом уроке подробно разберем статические и динамические маршруты, а также рассмотрим вложенные<em>urlpatterns</em>и обратные маршруты.</p>
7 <h2>Статические маршруты</h2>
7 <h2>Статические маршруты</h2>
8 <p>Мы с вами уже описали один статический маршрут:</p>
8 <p>Мы с вами уже описали один статический маршрут:</p>
9 <p>Здесь path сопоставляет образец '' с вьюхой views.index. Образец "пустая строка" соответствует пустому пути - запросам главной страницы сайта. Любой не пустой путь не совпадет с таким образцом. Статические образцы обычно описываются строками вида fruits/apples/golden_one и ожидают запросов строго по этому же пути.</p>
9 <p>Здесь path сопоставляет образец '' с вьюхой views.index. Образец "пустая строка" соответствует пустому пути - запросам главной страницы сайта. Любой не пустой путь не совпадет с таким образцом. Статические образцы обычно описываются строками вида fruits/apples/golden_one и ожидают запросов строго по этому же пути.</p>
10 <p>Имя домена не фигурирует в<em>urlpatterns</em>, что позволяет размещать одно и то же приложение на любом домене.</p>
10 <p>Имя домена не фигурирует в<em>urlpatterns</em>, что позволяет размещать одно и то же приложение на любом домене.</p>
11 <h2>Динамические маршруты</h2>
11 <h2>Динамические маршруты</h2>
12 <p>Авторы Django - сторонники использования читаемых URL. Это означает, что маршруты в Django-приложениях выглядят так, что понятно, куда ведет путь. Например, по пути /users/42/pets/101/med_info/ можно догадаться, что запрашивается медицинская информация (med_info) для питомца с идентификатором 101 (pets/101). Он принадлежит пользователю с идентификатором 42 (user/42).</p>
12 <p>Авторы Django - сторонники использования читаемых URL. Это означает, что маршруты в Django-приложениях выглядят так, что понятно, куда ведет путь. Например, по пути /users/42/pets/101/med_info/ можно догадаться, что запрашивается медицинская информация (med_info) для питомца с идентификатором 101 (pets/101). Он принадлежит пользователю с идентификатором 42 (user/42).</p>
13 <p>Иногда получается пойти дальше и вместо идентификаторов использовать имена. Например, такое возможно для имен пользователей, которые обычно уникальны в пределах системы. URL при использовании имен может выглядеть так: /users/~bob/books/.</p>
13 <p>Иногда получается пойти дальше и вместо идентификаторов использовать имена. Например, такое возможно для имен пользователей, которые обычно уникальны в пределах системы. URL при использовании имен может выглядеть так: /users/~bob/books/.</p>
14 <p>Пути, которые включают в себя данные - идентификаторы и имена - называются динамическими. И динамические маршруты используются как раз с такими путями.</p>
14 <p>Пути, которые включают в себя данные - идентификаторы и имена - называются динамическими. И динамические маршруты используются как раз с такими путями.</p>
15 <p>В образце, который описывает динамический маршрут, указываются именованные динамические участки. Каждый такой участок обрабатывает свою часть пути и определяет значение для аргумента, который будет передан во view. В итоге от view уже не требуется какая-либо обработка пути, хотя это и возможно.</p>
15 <p>В образце, который описывает динамический маршрут, указываются именованные динамические участки. Каждый такой участок обрабатывает свою часть пути и определяет значение для аргумента, который будет передан во view. В итоге от view уже не требуется какая-либо обработка пути, хотя это и возможно.</p>
16 <p>Опишем<em>urlpatterns</em>для примера пути, который приведен выше:</p>
16 <p>Опишем<em>urlpatterns</em>для примера пути, который приведен выше:</p>
17 <p>Здесь &lt;int:XXX&gt; означает ту самую динамическую часть пути. int означает, что в этом участке пути ожидается целое число в виде строки. Если сервер получит запрос по пути /users/42/pets/101/med_info/, маршрутизация закончится вызовом вью med_info_view(request, user_id=42, pet_id=101).</p>
17 <p>Здесь &lt;int:XXX&gt; означает ту самую динамическую часть пути. int означает, что в этом участке пути ожидается целое число в виде строки. Если сервер получит запрос по пути /users/42/pets/101/med_info/, маршрутизация закончится вызовом вью med_info_view(request, user_id=42, pet_id=101).</p>
18 <p>Кроме int Django предоставляет и другие преобразователи путей - path converters. Более того, можно определять и собственные. А если пути специфические, то всегда можно использовать регулярные выражения, чтобы выделить интересные нам части пути.</p>
18 <p>Кроме int Django предоставляет и другие преобразователи путей - path converters. Более того, можно определять и собственные. А если пути специфические, то всегда можно использовать регулярные выражения, чтобы выделить интересные нам части пути.</p>
19 <h3>Вложенные urlpatterns</h3>
19 <h3>Вложенные urlpatterns</h3>
20 <p>Иногда маршрутов становится слишком много и среди них намечаются группы, у которых общая статическая часть. Например, это маршруты ко views одного приложения. В этом случае стоит воспользоваться возможностью включения одних<em>urlpatterns</em>в другие.</p>
20 <p>Иногда маршрутов становится слишком много и среди них намечаются группы, у которых общая статическая часть. Например, это маршруты ко views одного приложения. В этом случае стоит воспользоваться возможностью включения одних<em>urlpatterns</em>в другие.</p>
21 <p>Предположим, у нас в проекте есть приложение project.users, в котором все views находятся под общим префиксом<em>/users/</em>. Нам достаточно создать модуль project.users.urls с описанием<em>urlpatterns</em>уже без префикса и подключить модуль в корневой project.urls:</p>
21 <p>Предположим, у нас в проекте есть приложение project.users, в котором все views находятся под общим префиксом<em>/users/</em>. Нам достаточно создать модуль project.users.urls с описанием<em>urlpatterns</em>уже без префикса и подключить модуль в корневой project.urls:</p>
22 <p>В новом наборе<em>urlpatterns</em>у образцов нет префикса<em>users</em>. А в основном<em>urlpatterns</em>указано, что все пути, которые начинаются с<em>users</em>, нужно сопоставлять с образцами из project.users.urls.</p>
22 <p>В новом наборе<em>urlpatterns</em>у образцов нет префикса<em>users</em>. А в основном<em>urlpatterns</em>указано, что все пути, которые начинаются с<em>users</em>, нужно сопоставлять с образцами из project.users.urls.</p>
23 <p>Мы подключили вложенные urlpatterns с помощью функции django.urls.include и указали модуль в виде строки. Можно импортировать модуль и указать вместо цели маршрута сразу его: path('users/', project.users.urls) - эти два варианта эквивалентны. Но неявное подключение вместо импорта решает одну важную задачу: избавляет от потенциальных циклических импортов.</p>
23 <p>Мы подключили вложенные urlpatterns с помощью функции django.urls.include и указали модуль в виде строки. Можно импортировать модуль и указать вместо цели маршрута сразу его: path('users/', project.users.urls) - эти два варианта эквивалентны. Но неявное подключение вместо импорта решает одну важную задачу: избавляет от потенциальных циклических импортов.</p>
24 <p>Ранее мы закомментировали в нашем мини-проекте строчку path('admin/', admin.site.urls). Это тоже включение админки в нашу карту маршрутов по префиксу<em>admin</em>. Подобным образом в приложение часто подключаются сторонние пакеты, у которых собственные маршруты.</p>
24 <p>Ранее мы закомментировали в нашем мини-проекте строчку path('admin/', admin.site.urls). Это тоже включение админки в нашу карту маршрутов по префиксу<em>admin</em>. Подобным образом в приложение часто подключаются сторонние пакеты, у которых собственные маршруты.</p>
25 <h3>Обратные маршруты или reverse</h3>
25 <h3>Обратные маршруты или reverse</h3>
26 <p>Часто нужно получить для определенного маршрута правильный путь. Например, необходимо кому-то дать ссылку на медицинскую карточку питомца пользователя. Если мы будем вручную собирать путь из строк, то при изменениях в маршруте новый путь может стать некорректным.</p>
26 <p>Часто нужно получить для определенного маршрута правильный путь. Например, необходимо кому-то дать ссылку на медицинскую карточку питомца пользователя. Если мы будем вручную собирать путь из строк, то при изменениях в маршруте новый путь может стать некорректным.</p>
27 <p>Чтобы была возможность для любого маршрута всегда получить правильный путь, нужно произвести операцию, обратную маршрутизации - у Django есть функции<a>reverse</a>и<a>reverse_lazy</a>. Они позволяют получить путь по имени маршрута. Поэтому маршруты, которые нужно обращать, необходимо поименовать (задать уникальное имя):</p>
27 <p>Чтобы была возможность для любого маршрута всегда получить правильный путь, нужно произвести операцию, обратную маршрутизации - у Django есть функции<a>reverse</a>и<a>reverse_lazy</a>. Они позволяют получить путь по имени маршрута. Поэтому маршруты, которые нужно обращать, необходимо поименовать (задать уникальное имя):</p>
28 <p>Когда маршрут поименован, можно получить путь вызовом вида reverse('pet_med_info', kwargs={'user_id': 42, 'pet_id': 101}). Как бы ни менялась маршрутизация в дальнейшем, пока путь содержит те же именованные участки и назван по-старому, эта функция будет давать актуальный для маршрута путь.</p>
28 <p>Когда маршрут поименован, можно получить путь вызовом вида reverse('pet_med_info', kwargs={'user_id': 42, 'pet_id': 101}). Как бы ни менялась маршрутизация в дальнейшем, пока путь содержит те же именованные участки и назван по-старому, эта функция будет давать актуальный для маршрута путь.</p>
29 <p>Функция reverse_lazy нужна, когда путь нужно получить на этапе инициализации программы, например, при описании class based views. Во время инициализации путь может потребоваться до того, как вся карта маршрутов будет построена. И тут функция reverse_lazy всего лишь оставляет обещание вернуть путь, когда он реально понадобится - когда сервер уже начнет отвечать на запросы.</p>
29 <p>Функция reverse_lazy нужна, когда путь нужно получить на этапе инициализации программы, например, при описании class based views. Во время инициализации путь может потребоваться до того, как вся карта маршрутов будет построена. И тут функция reverse_lazy всего лишь оставляет обещание вернуть путь, когда он реально понадобится - когда сервер уже начнет отвечать на запросы.</p>
30 <p>В итоге reverse_lazy используем в атрибутах классов, а в теле вьюх и шаблонах - reverse. Последняя работает быстрее, но только с готовой картой маршрутов.</p>
30 <p>В итоге reverse_lazy используем в атрибутах классов, а в теле вьюх и шаблонах - reverse. Последняя работает быстрее, но только с готовой картой маршрутов.</p>