что обратное () в Джанго


220

Когда я иногда читаю код django, я вижу в некоторых шаблонах reverse(). Я не совсем уверен, что это такое, но он используется вместе с HttpResponseRedirect. Как и когда это reverse()должно быть использовано?

Было бы хорошо, если бы кто-то дал ответ с некоторыми примерами ...


27
Учитывая шаблон URL, Django использует url (), чтобы выбрать правильный вид и создать страницу. То есть url--> view name. Но иногда, как при перенаправлении, вам нужно пойти в обратном направлении и дать Django имя представления, и Django генерирует соответствующий URL. Другими словами, view name --> url. То есть reverse()(это обратная функция url). Это может показаться более прозрачным, если просто назвать его, generateUrlFromViewNameно это слишком долго и, вероятно, недостаточно широко
eric

4
@neuronet Отличное объяснение, спасибо. Это имя показалось (и кажется) особенно не интуитивным для меня, что я считаю тяжким грехом. Кто не ненавидит ненужную путаницу?
Майк Грызун

Это типичный пример именования, который подчеркивает один аспект сущности (например, функцию), который был в центре внимания программиста в то время, учитывая его контекст, но не является наиболее полезным вариантом в широком контексте любого другого разработчика. , Мы часто попадаем в эту ловушку как программисты - наименование так важно для обнаружения, что стоит остановиться и подумать о различных контекстах и ​​выбрать наиболее подходящий.
Корнел Массон

Ответы:


349

reverse()| Джанго документация


Давайте предположим, что в вашем urls.pyвы определили это:

url(r'^foo$', some_view, name='url_name'),

В шаблоне вы можете ссылаться на этот URL как:

<!-- django <= 1.4 -->
<a href="{% url url_name %}">link which calls some_view</a>

<!-- django >= 1.5 or with {% load url from future %} in your template -->
<a href="{% url 'url_name' %}">link which calls some_view</a>

Это будет представлено как:

<a href="/foo/">link which calls some_view</a>

Теперь предположим, что вы хотите сделать что-то похожее в вашем views.py- например, вы обрабатываете другой URL (не /foo/) в другом представлении (не some_view) и хотите перенаправить пользователя /foo/(часто это происходит при успешной отправке формы).

Вы могли бы просто сделать:

return HttpResponseRedirect('/foo/')

Но что, если вы хотите изменить URL в будущем? Вы должны обновить свой urls.py и все ссылки на него в своем коде. Это нарушает « СУХОЙ» («Не повторяй себя») , всю идею редактирования только одного места, к чему нужно стремиться.

Вместо этого вы можете сказать:

from django.urls import reverse
return HttpResponseRedirect(reverse('url_name'))

Это просматривает все URL-адреса, определенные в вашем проекте для URL-адреса, определенного с именем, url_nameи возвращает фактический URL-адрес /foo/.

Это означает, что вы обращаетесь к URL-адресу только по его nameатрибуту - если вы хотите изменить сам URL-адрес или представление, к которому он относится, вы можете сделать это, отредактировав только одно место - urls.py.


3
К вашему сведению, {{ url 'url_name' }}должно быть {% url url_name %}в Django 1.4 или ранее. Это изменится в следующем выпуске Django (1.5) и должно быть {% url 'url_name' %}. Документы для тега шаблона URL дают некоторую полезную информацию, если вы прокрутите немного вниз до раздела «
прямая

1
j_syk спасибо - я делаю @load url из будущего @, так как вышла 1.3 и забыла, что это еще не значение по умолчанию. Я обновлю свой ответ, чтобы он не сбил с толку неопытного.
сцена

2
исправлено - я думаю, что для вас вполне приемлемо самостоятельно редактировать глупые опечатки в ответах других людей, так что если вы видите больше, просто прыгайте :-)
scytale

3
Один из самых тонких ответов можно найти на этом сайте.
Манас Чатурведи

1
«>>> но что если вы захотите изменить URL в будущем», эти тонкости полезны в 0,0001% случаев, и решение поставляется как полезная функция, и люди используют его так, как будто это так ». лучшие практики »и оставьте беспорядок. TBH, если при изменении URL в будущем вы просто делаете глобальную замену. Даже это решение (используйте url_name) склонно к проблеме «что если вы захотите изменить url_name в будущем?» Кодирую в Django уже более 5 лет, и все же для удовлетворения потребностей url_reverse. Лучший способ справиться с такими странностями - отказаться от их использования.
Нехем

10

Это старый вопрос, но кое-что может кому-то помочь.

Из официальных документов:

Django предоставляет инструменты для выполнения реверсирования URL, которые соответствуют разным слоям, где необходимы URL: В шаблонах: Использование тега шаблона URL. В коде Python: использование функции reverse (). В коде более высокого уровня, связанном с обработкой URL-адресов экземпляров модели Django: метод get_absolute_url ().

Например. в шаблонах (тег URL)

<a href="{% url 'news-year-archive' 2012 %}">2012 Archive</a>

Например. в коде Python (используя reverseфункцию)

return HttpResponseRedirect(reverse('news-year-archive', args=(year,)))

1
нужно полное описание босс
датьJob

ОП особо упомянул, что он читает документы, ему нужно объяснение, а не просто копировать / вставлять из документов.
Руси

8

Существующие ответы проделали большую работу по объясняя , что этой reverse()функции в Django.

Тем не менее, я надеялся, что мой ответ пролил другой свет на вопрос « почему» : зачем использовать reverse()вместо других более простых, возможно, более питонических подходов в связывании шаблонов и каковы некоторые законные причины популярности этого «перенаправления через reverse() шаблон "в логике маршрутизации Django.

Одним из ключевых преимуществ является обратная конструкция URL, как уже упоминали другие. Так же, как вы будете использовать {% url "profile" profile.id %}для генерации URL из файла конфигурации вашего приложения: например path('<int:profile.id>/profile', views.profile, name="profile").

Но, как отметил ФП, использование reverse()также обычно сочетается с использованием HttpResponseRedirect. Но почему?

Я не совсем уверен, что это такое, но он используется вместе с HttpResponseRedirect. Как и когда должен использоваться этот reverse ()?

Учтите следующее views.py:

from django.http import HttpResponseRedirect
from django.urls import reverse

def vote(request, question_id):
    question = get_object_or_404(Question, pk=question_id)
    try:
        selected = question.choice_set.get(pk=request.POST['choice'])
    except KeyError:
        # handle exception
        pass
    else:
        selected.votes += 1
        selected.save()
        return HttpResponseRedirect(reverse('polls:polls-results',
                                    args=(question.id)
        ))

И наш минимальный urls.py:

from django.urls import path
from . import views

app_name = 'polls'
urlpatterns = [
    path('<int:question_id>/results/', views.results, name='polls-results'),
    path('<int:question_id>/vote/', views.vote, name='polls-vote')
]

В vote()функции код в нашем elseблоке используется reverseвместе со HttpResponseRedirectследующим шаблоном:

HttpResponseRedirect(reverse('polls:polls-results',
                                        args=(question.id)

Это, прежде всего, означает, что нам не нужно жестко кодировать URL (в соответствии с принципом DRY), но, что более важно, reverse()предоставляет элегантный способ создания строк URL, обрабатывая значения, распакованные из аргументов ( args=(question.id)обрабатывается URLConfig). Предполагается, что questionимеет атрибут, idкоторый содержит значение 5, а URL-адрес, созданный из reverse()этого:

'/polls/5/results/'

В обычном коде связывания представления шаблона мы используем HttpResponse()или, render()поскольку они обычно включают меньше абстракции: одна функция представления возвращает один шаблон:

def index(request):
    return render(request, 'polls/index.html') 

Но во многих законных случаях перенаправления мы обычно заботимся о создании URL-адреса из списка параметров. К ним относятся такие случаи, как:

  • Отправка HTML-формы по POSTзапросу
  • Пост-проверка логина пользователя
  • Сбросить пароль через веб-токены JSON

Большинство из них включают в себя некоторую форму перенаправления и URL-адрес, созданный с помощью набора параметров. Надеюсь, что это добавляет к уже полезной ветке ответов!


4

Функция поддерживает сухой принцип - гарантирует, что вы не будете использовать жесткий код в своем приложении. URL-адрес должен быть определен в одном месте, и только в одном месте - ваш URL-адрес конф. После этого вы просто ссылаетесь на эту информацию.

Используйте, reverse()чтобы дать вам URL страницы, указав либо путь к представлению, либо параметр page_name из вашей ссылки url. Вы бы использовали его в тех случаях, когда это не имеет смысла делать в шаблоне с {% url 'my-page' %}.

Есть много возможных мест, где вы могли бы использовать эту функцию. Я нашел его в одном месте, когда перенаправляю пользователей в виде (часто после успешной обработки формы) -

return HttpResponseRedirect(reverse('thanks-we-got-your-form-page'))

Вы также можете использовать его при написании шаблонов тегов.

В другой раз я использовал reverse()модель с наследованием. У меня был ListView на родительской модели, но я хотел получить от любого из этих родительских объектов к DetailView своего связанного дочернего объекта. Я прикрепил get__child_url()функцию к родителю, которая идентифицировала существование дочернего элемента и вернула URL его DetailView, используя reverse().



2

Существующие ответы вполне понятны. На тот случай, если вы не знаете, почему он вызывается reverse: он вводит имя URL-адреса и дает фактический URL-адрес, обратный первому URL-адресу, а затем дает ему имя.


1
Просто учу Джанго из учебника (Django Girls). Это крутая кривая обучения. Я думаю, что название этой функции ужасно: «резерв» без каких-либо оговорок ОЧЕНЬ СИЛЬНО предлагает зарезервировать список или строку, которая, очевидно, не имеет к этому никакого отношения.
Майк Грызун

@mikerodent Я полностью с тобой согласен. Кроме того, ни один из этих ответов не объясняет, почему функция называется обратной. Это такое плохое имя имо.
Сохам Донгаргаонкар

1

Reverse () используется для соблюдения принципа DRY django, т. Е. Если вы измените URL в будущем, вы можете ссылаться на этот URL с помощью reverse (urlname).

Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.