DCR
DCR

Reputation: 15665

Django HttpResponseRedirect versus redirect

Given the following:

def add(request):    
    if request.method == "POST":
        task = request.POST.get('task')        
        form = NewTaskForm(request.POST)
        if form.is_valid():
            task = form.cleaned_data["task"]            
            request.session['tasks'] += [task]           
        
            # return HttpResponseRedirect(reverse("tasks:index"))
            return redirect('tasks:index')
        
        else:
            return render(request, "tasks/add.html",{
                "form": form
            })
    return render(request, "tasks/add.html",{
        "form": NewTaskForm()
    })

what's the difference, why would you use one over the other, between:

return HttpResponseRedirect(reverse("tasks:index"))

and:

return redirect('tasks:index')

Upvotes: 2

Views: 2426

Answers (2)

dotslash227
dotslash227

Reputation: 408

There's no difference, in terms of functionality, in terms of readability, yes!

HttpResponseRedirect comes from django.http library and redirect() comes from django.shortcuts library.

It's the same like using the either the render() [comes from django.shortcuts] function or TemplateResponse() [comes from django.templates]

Upvotes: 1

willeM_ Van Onsem
willeM_ Van Onsem

Reputation: 476659

redirect(…) is implemented as [GitHub]:

def redirect(to, *args, permanent=False, **kwargs):
    redirect_class = HttpResponsePermanentRedirect if permanent else HttpResponseRedirect
    return redirect_class(resolve_url(to, *args, **kwargs))

where resolve_url is a layer around the reverse(…) function [Django-doc], as we can see in the source code [GitHub]:

def resolve_url(to, *args, **kwargs):
    """
    Return a URL appropriate for the arguments passed.
    The arguments could be:
        * A model: the model's `get_absolute_url()` function will be called.
        * A view name, possibly with arguments: `urls.reverse()` will be used
          to reverse-resolve the name.
        * A URL, which will be returned as-is.
    """
    # If it's a model, use get_absolute_url()
    if hasattr(to, 'get_absolute_url'):
        return to.get_absolute_url()

    if isinstance(to, Promise):
        # Expand the lazy instance, as it can cause issues when it is passed
        # further to some Python functions like urlparse.
        to = str(to)

    if isinstance(to, str):
        # Handle relative URLs
        if to.startswith(('./', '../')):
            return to

    # Next try a reverse URL resolution.
    try:
        return reverse(to, args=args, kwargs=kwargs)
    except NoReverseMatch:
        # If this is a callable, re-raise.
        if callable(to):
            raise
        # If this doesn't "feel" like a URL, re-raise.
        if '/' not in to and '.' not in to:
            raise

    # Finally, fall back and assume it's a URL
    return to

It is thus a more "rich" way to resolve URL's since:

  1. if the object has a .get_absolute_url() method [Django-doc] it will return the result of this method;
  2. if is a Promise, it will evaluate the promise;
  3. if it is a relative URL, it will return the URL; and
  4. if the reverse(…) fails and it looks like a URL, it will return the value you passed itself, since then it assumes it is an (absolute) URL.

It thus does not only aim to find a view with that name, but does some extra things.

Furthermore the way you use parameters is more convenient with redirect. If the url looks like:

app_name = 'tasks'

urlpatterns = [
    # …,
    path('page/<slug:myslug>/', some_view, name='page')
]

then when you use reverse(…), you provide a value for the myslug parameter with:

return HttpResponseRedirect(reverse('tasks:index', args=('value',)))

or:

return HttpResponseRedirect(reverse('tasks:index', kwargs={'myslug': 'value'}))

whereas with a redirect, you can use:

return redirect('tasks:index', 'value')

or:

return redirect('tasks:index', myslug='value')

Upvotes: 3

Related Questions