ChatGPT解决这个技术问题 Extra ChatGPT

What is reverse()?

When I read Django code sometimes, I see in some templates reverse(). I am not quite sure what this is but it is used together with HttpResponseRedirect. How and when is this reverse() supposed to be used?

Given a url pattern, Django uses url() to pick the right view and generate a page. That is, url--> view name. But sometimes, like when redirecting, you need to go in the reverse direction and give Django the name of a view, and Django generates the appropriate url. In other words, view name --> url. That is, reverse() (it's the reverse of the url function). It might seem more transparent to just call it generateUrlFromViewName but that's too long and probably not general enough: docs.djangoproject.com/en/dev/topics/http/urls/…
@neuronet Great explanation, thanks. This name seemed (and seems) particularly non-intuitive to me, which I hold to be a grave sin. Who doesn't hate unnecessary obfuscation?
This is a typical example of naming that emphasises one aspect of an entity (e.g. function) that was foremost in the mind of the programmer at the time, given his context, but is not the most useful option in the broad context of any other developer. We often fall into this trap as programmers - naming is so important for discoverability, it's worth stopping and thinking about the different contexts and choosing the most appropriate one.

S
Sabito 錆兎 stands with Ukraine

reverse() | Django documentation

Let's suppose that in your urls.py you have defined this:

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

In a template you can then refer to this url as:

<!-- 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>

This will be rendered as:

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

Now say you want to do something similar in your views.py - e.g. you are handling some other URL (not /foo/) in some other view (not some_view) and you want to redirect the user to /foo/ (often the case on successful form submission).

You could just do:

return HttpResponseRedirect('/foo/')

But what if you want to change the URL in the future? You'd have to update your urls.py and all references to it in your code. This violates the DRY (Don't Repeat Yourself) principle and the whole idea of editing in one place only - which is something to strive for.

Instead, you can say:

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

This looks through all URLs defined in your project for the URL defined with the name url_name and returns the actual URL /foo/.

This means that you refer to the URL only by its name attribute - if you want to change the URL itself or the view it refers to you can do this by editing one place only - urls.py.


FYI, {{ url 'url_name' }} should be {% url url_name %} in Django 1.4 or earlier. This will be changing in the next Django release (1.5) and should then be {% url 'url_name' %}. The docs for the url templatetag give some good info if you scroll down a bit to the "forwards compatibility" section
j_syk thanks - i've been doing @load url from future@ since 1.3 came out and forgot that it's not yet the default. I'll update my answer so it doesn't trip up the inexperienced.
not to be too critical, and to continue on the theme of not tripping up the inexperienced, but it should be block tags {% %} not variable tags {{ }} for the url tag :)
fixed - I think it's considered totally acceptable for you to edit dumb typos in other people's answers yourself so if you see more just jump in :-)
">>>but what if you want to change the url in future", These kinds of subtleties that are useful on .0001% of the time and the solution is shipped like a useful feature, and people use it as if they are 'best practices' and leave the mess. TBH if when one changes the urls in future you just do a global find-replace. Even this solution(use url_name) is prone to the problem of 'what if you want to change the url_name in future?' Been coding in Django for over 5 years and yet to meet the need for url_reverse. The best way to deal with these kinds of oddities is to refuse to use them.
y
yyFred

The existing answers are quite clear. Just in case you do not know why it is called reverse: It takes an input of a url name and gives the actual url, which is reverse to having a url first and then give it a name.


Just learning Django from a tutorial (Django Girls). It's a steep learning curve. I think this function's name is dreadful: "reserve" without any qualification VERY STRONGLY suggests reserving a list or string, which obviously has nothing whatsoever to do with it.
@mikerodent I completely agree with you. Besides, none of these answers explain why the function is called reverse. It's such a bad name imo.
o
onlyphantom

Existing answers did a great job at explaining the what of this reverse() function in Django.

However, I'd hoped that my answer shed a different light at the why: why use reverse() in place of other more straightforward, arguably more pythonic approaches in template-view binding, and what are some legitimate reasons for the popularity of this "redirect via reverse() pattern" in Django routing logic.

One key benefit is the reverse construction of a url, as others have mentioned. Just like how you would use {% url "profile" profile.id %} to generate the url from your app's url configuration file: e.g. path('<int:profile.id>/profile', views.profile, name="profile").

But as the OP have noted, the use of reverse() is also commonly combined with the use of HttpResponseRedirect. But why?

I am not quite sure what this is but it is used together with HttpResponseRedirect. How and when is this reverse() supposed to be used?

Consider the following 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)
        ))

And our minimal 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')
]

In the vote() function, the code in our else block uses reverse along with HttpResponseRedirect in the following pattern:

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

This first and foremost, means we don't have to hardcode the URL (consistent with the DRY principle) but more crucially, reverse() provides an elegant way to construct URL strings by handling values unpacked from the arguments (args=(question.id) is handled by URLConfig). Supposed question has an attribute id which contains the value 5, the URL constructed from the reverse() would then be:

'/polls/5/results/'

In normal template-view binding code, we use HttpResponse() or render() as they typically involve less abstraction: one view function returning one template:

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

But in many legitimate cases of redirection, we typically care about constructing the URL from a list of parameters. These include cases such as:

HTML form submission through POST request

User login post-validation

Reset password through JSON web tokens

Most of these involve some form of redirection, and a URL constructed through a set of parameters. Hope this adds to the already helpful thread of answers!


m
mc_kaiser

This is an old question, but here is something that might help someone.

From the official docs:

Django provides tools for performing URL reversing that match the different layers where URLs are needed: In templates: Using the url template tag. In Python code: Using the reverse() function. In higher level code related to handling of URLs of Django model instances: The get_absolute_url() method.

Eg. in templates (url tag)

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

Eg. in python code (using the reverse function)

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

need full description boss
OP specifically mentioned that he read the docs, he needed explanation, not just copy/paste from the docs.
A
Ashish Kumar Sahoo

The function supports the dry principle - ensuring that you don't hard code urls throughout your app. A url should be defined in one place, and only one place - your url conf. After that you're really just referencing that info.

Use reverse() to give you the url of a page, given either the path to the view, or the page_name parameter from your url conf. You would use it in cases where it doesn't make sense to do it in the template with {% url 'my-page' %}.

There are lots of possible places you might use this functionality. One place I've found I use it is when redirecting users in a view (often after the successful processing of a form)-

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

You might also use it when writing template tags.

Another time I used reverse() was with model inheritance. I had a ListView on a parent model, but wanted to get from any one of those parent objects to the DetailView of it's associated child object. I attached a get__child_url() function to the parent which identified the existence of a child and returned the url of it's DetailView using reverse().


e
eric

There is a doc for that

https://docs.djangoproject.com/en/dev/topics/http/urls/#reverse-resolution-of-urls

it can be used to generate an URL for a given view

main advantage is that you do not hard code routes in your code.


S
Samsul Islam

The reverse() is used to adhere the django DRY principle i.e if you change the url in future then you can reference that url using reverse(urlname).