Возвращение URL-адресов¶
Центральной особенностью, отличающей архитектурный стиль REST от других сетевых стилей, является акцент на едином интерфейсе между компонентами.
‒ Рой Филдинг, >.
Как правило, лучше возвращать абсолютные URI из ваших Web API, например http://example.com/foobar , а не относительные URI, например /foobar .
Преимуществами этого являются:
- Это более четко выражено.
- Это оставляет меньше работы для ваших клиентов API.
- Нет никакой двусмысленности относительно значения строки, когда она встречается в таких представлениях, как JSON, которые не имеют собственного типа URI.
- С его помощью легко делать такие вещи, как разметка HTML-представлений с гиперссылками.
Фреймворк REST предоставляет две служебные функции для упрощения возврата абсолютных URI из вашего Web API.
Использовать их не обязательно, но если вы их используете, то самоописывающийся API сможет автоматически делать для вас гиперссылки на свой вывод, что значительно упростит просмотр API.
обратный¶
Подпись: reverse(viewname, *args, **kwargs)
Имеет такое же поведение, как ** «django.urls.reverse :doc:` `** , за исключением того, что возвращает полностью определенный URL, используя запрос для определения хоста и порта.
Вы должны включить запрос в качестве аргумента ключевого слова в функцию, например:
from rest_framework.reverse import reverse from rest_framework.views import APIView from django.utils.timezone import now class APIRootView(APIView): def get(self, request): year = now().year data = . 'year-summary-url': reverse('year-summary', args=[year], request=request) > return Response(data)
обратная_лентяйка¶
Подпись: reverse_lazy(viewname, *args, **kwargs)
Имеет такое же поведение, как ** «django.urls.reverse_lazy :doc:` `** , за исключением того, что возвращает полностью определенный URL, используя запрос для определения хоста и порта.
Как и в случае с функцией reverse , вы должны включить запрос в качестве аргумента ключевого слова в функцию, например:
api_root = reverse_lazy('api-root', request=request)
Перенаправления (redirect). Функция reverse
В Django подобные редиректы достаточно просто выполняются с помощью функции: django.shortcuts.redirect Давайте для примера сделаем перенаправление со страницы архива, если год больше 2023:
def archive(request, year): if year > 2023: return redirect('/') return HttpResponse(f"Архив по годам
")
Здесь в качестве первого параметра указывается страница, на которую происходит перенаправление, в данном случае – это главная страница сайта. Также в файле settings.py вернем прежнее значение параметра DEBUG:
DEBUG = True
Если теперь выполнить запрос: 127.0.0.1:8000/archive/2024/ то мы попадем на главную страницу с кодом перенаправления 302 (см. консоль). Если же нам нужно указать постоянный редирект с кодом 301, то записывается дополнительный параметр:
return redirect('/', permanent=True)
Вообще в качестве первого аргумента функции redirect() можно передавать не только конкретный URL, но и представление. В частности, вместо ‘/’ можно передать ссылку на функцию index следующим образом:
return redirect(index, permanent=True)
В данном случае это будет одно и то же.
Классы HttpResponseRedirect и HttpResponsePermanentRedirect
- HttpResponseRedirect – для редиректа с кодом 302;
- HttpResponsePermanentRedirect – для редиректа с кодом 301
def archive(request, year): if year > 2023: return HttpResponseRedirect('/') return HttpResponse(f"Архив по годам
")
На самом деле функция redirect() использует в своей работе эти классы, но, вместе с тем, она несколько более гибкая. Поэтому какой вариант выбирать решает сам программист, исходя из логики построения кода.
Параметр name функции path
Однако указывать в функции redirect, да и вообще где бы то ни было в приложении конкретный URL-адрес (кроме их списка в коллекции urlpatterns) – это порочная практика, или, как еще говорят – хардкодинг. Вместо этого каждому шаблону пути можно присвоить свое уникальное имя и использовать его в рамках всего проекта. Давайте определим имена для наших URL-запросов. Для этого перейдем в файл women/urls.py и в каждой функции path пропишем параметр name с уникальными именами:
urlpatterns = [ path('', views.index, name='home'), path('cats//', views.categories_by_slug, name='cats'), path('cats//', views.categories, name='cats_id'), re_path(r'^archive/(?P[0-9])/', views.archive, name='archive'), ]
Конечно, эти имена вы можете выбрать и другие – это лишь пример. И далее, в функции redirect мы можем выполнить перенаправление на главную страницу, указав имя home:
return redirect('home', permanent=True)
Как видите, это гораздо понятнее и безопаснее использования конкретных URL-адресов. Если в дальнейшем маршрут изменится, то автоматически изменится и адрес перенаправления для home.
Функция reverse()
Если же маршрут помимо имени содержит еще параметры, как например, маршрут ‘cats’ с параметром slug, то для корректного перенаправления необходимо в функции redirect() вторым и последующими аргументами передать требуемые параметры. В нашем случае это можно сделать так:
return redirect('cats', 'music')
В результате, функция redirect() вычислит следующий URL: http://127.0.0.1:8000/cats/music/ и сделает на него перенаправление. Но мы можем разделить операции вычисления URL и непосредственно перенаправление. Для этого в Django имеется функция: django.urls.reverse() которая возвращает строку URL-адреса, вычисленный на основе переданного имени и набора аргументов. Например, для вычисления адреса маршрута cats с параметром ‘music’ функцию reverse() можно вызвать следующим образом:
url_redirect = reverse('cats', args=('music', ))
А, затем, передать этот маршрут в функцию reverse():
return redirect(url_redirect)
или в соответствующий класс:
return HttpResponsePermanentRedirect(url_redirect)
Зачем нужен reverse()?
Всем привет, прочитал доку, вроде бы и понятно, но как-то непонятно. Кто может понятно объяснить, зачем нужен reverse()? Зачем он нужен в принципе и зачем он нужен в частности в get_absolute_url?
- Вопрос задан более трёх лет назад
- 5549 просмотров
1 комментарий
Простой 1 комментарий
Сергей Горностаев @sergey-gornostaev Куратор тега Django
Метод get_absolute_url должен возвращать url представления для текущего экземпляра модели. Как вы собираетесь возвращать его без reverse ?
Решения вопроса 1

reverse позволяет по имени вьюхи получить её url.
from news import views path('archive/', views.archive, name='news-archive')
from django.urls import reverse reverse('news-archive')
get_absolute_url — позволяет получить канонический URL обьекта, при условии что этот метод определён.
# Можно так: def get_absolute_url(self): return "/people/%i/" % self.id # Но лучше так: def get_absolute_url(self): from django.urls import reverse return reverse('people.views.details', args=[str(self.id)])
spoiler
>">Link >">Link
django.urls функции полезности¶
Если вам нужно использовать в своем коде что-то похожее на тег шаблона url , Django предоставляет следующую функцию:
reverse ( viewname , urlconf = None , args = None , kwargs = None , current_app = None ) [исходный код] ¶
viewname может быть URL pattern name или вызываемым объектом представления. Например, учитывая следующее url :
from news import views path("archive/", views.archive, name="news-archive")
вы можете использовать любой из следующих способов, чтобы изменить URL:
# using the named URL reverse("news-archive") # passing a callable object # (This is discouraged because you can't reverse namespaced views this way.) from news import views reverse(views.archive)
Если URL принимает аргументы, вы можете передать их в формате args . Например:
from django.urls import reverse def myview(request): return HttpResponseRedirect(reverse("arch-summary", args=[1945]))
Также можно передавать kwargs вместо args . Например:
>>> reverse("admin:app_list", kwargs="app_label": "auth">) '/admin/auth/'
args и kwargs не могут быть переданы в reverse() одновременно.
Если совпадение невозможно, reverse() вызывает исключение NoReverseMatch .
Функция reverse() может отменить большое количество шаблонов регулярных выражений для URL, но не все возможные. Основным ограничением на данный момент является то, что шаблон не может содержать альтернативные варианты с использованием символа вертикальной черты ( «|» ). Вы вполне можете использовать такие шаблоны для сопоставления с входящими URL и отправки их в представления, но вы не можете обратить такие шаблоны.
Аргумент current_app позволяет вам предоставить подсказку преобразователю, указывающую на приложение, к которому принадлежит текущее выполняющееся представление. Этот аргумент current_app используется в качестве подсказки для преобразования пространств имен приложений в URL-адреса конкретных экземпляров приложений в соответствии с namespaced URL resolution strategy .
Аргумент urlconf представляет собой модуль URLconf, содержащий шаблоны URL, которые следует использовать для реверсирования. По умолчанию используется корневой URLconf для текущего потока.
Строка, возвращаемая командой reverse() , уже является строкой urlquoted . Например:
>>> reverse("cities", args=["Orléans"]) '. /Orl%C3%A9ans/'
Применение дальнейшего кодирования (например, urllib.parse.quote() ) к выходу reverse() может привести к нежелательным результатам.
reverse_lazy() ¶
Лениво оцениваемая версия reverse().
reverse_lazy ( viewname , urlconf = None , args = None , kwargs = None , current_app = None )¶
Она полезна в тех случаях, когда необходимо использовать обратный URL до загрузки URLConf вашего проекта. Некоторые распространенные случаи, когда эта функция необходима:
- предоставление обратного URL в качестве атрибута url общего представления на основе класса.
- предоставление обратного URL декоратору (например, аргумент login_url для декоратора django.contrib.auth.decorators.permission_required() ).
- предоставление обратного URL в качестве значения по умолчанию для параметра в сигнатуре функции.
resolve() ¶
Функция resolve() может использоваться для преобразования URL-путей к соответствующим функциям представления. Она имеет следующую сигнатуру:
path — это путь URL, который вы хотите разрешить. Как и в случае с reverse() , вам не нужно беспокоиться о параметре urlconf . Функция возвращает объект ResolverMatch , который позволяет вам получить доступ к различным метаданным о разрешенном URL.
Если URL не разрешается, функция выдает исключение Resolver404 (подкласс Http404 ).
Функция представления, которая будет использоваться для обслуживания URL-адреса
Аргументы, которые будут переданы функции представления, как разобранные из URL.
Все аргументы ключевых слов, которые будут переданы в функцию представления, т.е. captured_kwargs и extra_kwargs .
Захваченные аргументы ключевых слов, которые будут переданы функции представления, как разобранные из URL.
Дополнительные аргументы ключевого слова, которые будут переданы в функцию представления.
Имя шаблона URL, который соответствует URL.
Маршрут, соответствующий шаблону URL.
Например, если path(‘users//’, . ) является совпадающим шаблоном, route будет содержать ‘users//’ .
Список шаблонов URL, опробованных до того, как URL либо совпал с одним, либо исчерпал доступные шаблоны.
Пространство имен приложения для шаблона URL, который соответствует URL.
Список отдельных компонентов пространства имен в полном пространстве имен приложения для шаблона URL, который соответствует URL. Например, если app_name будет ‘foo:bar’ , то app_names будет [‘foo’, ‘bar’] .
Пространство имен экземпляра для шаблона URL, который соответствует URL.
Список отдельных компонентов пространства имен в полном пространстве имен экземпляра для шаблона URL, который соответствует URL. т.е. если пространство имен foo:bar , то пространства имен будут [‘foo’, ‘bar’] .
Имя представления, которое соответствует URL, включая пространство имен, если оно есть.
Затем объект ResolverMatch может быть опрошен для получения информации о шаблоне URL, который соответствует URL:
# Resolve a URL match = resolve("/some/path/") # Print the URL pattern that matches the URL print(match.url_name)
Объект ResolverMatch также может быть присвоен тройке:
func, args, kwargs = resolve("/some/path/")
Одним из возможных вариантов использования resolve() может быть проверка того, будет ли представление выдавать ошибку Http404 перед перенаправлением на него:
from urllib.parse import urlparse from django.urls import resolve from django.http import Http404, HttpResponseRedirect def myview(request): next = request.META.get("HTTP_REFERER", None) or "/" response = HttpResponseRedirect(next) # modify the request and response as required, e.g. change locale # and set corresponding locale cookie view, args, kwargs = resolve(urlparse(next)[2]) kwargs["request"] = request try: view(*args, **kwargs) except Http404: return HttpResponseRedirect("/") return response
get_script_prefix() ¶
get_script_prefix () [исходный код] ¶
Обычно для определения URL-адресов внутри приложения всегда следует использовать reverse() . Однако, если ваше приложение само строит часть иерархии URL, вам иногда может понадобиться генерировать URL. В этом случае вам нужно уметь находить базовый URL проекта Django внутри его веб-сервера (обычно reverse() заботится об этом за вас). В этом случае вы можете вызвать get_script_prefix() , который вернет префиксную часть URL вашего проекта Django. Если ваш проект Django находится в корне своего веб-сервера, то это всегда «/» .
Эта функция не может использоваться вне цикла «запрос-ответ», поскольку она опирается на значения, инициализированные в этом цикле.