Django Redirect Explained

When building a Django web application, sometimes you’ll need to redirect a client request from the requested URL address to another URL address. In this article, we’ll see how to get the best out of Django redirect functionality. 

If you came here just to remind yourself how to use the Django redirect, here’s a short snippet you can use.

# views.py
from django.shortcuts import redirect

def redirect_view(request):
    return redirect('/redirect-to-this-url/')

Now, let’s see what are redirects, when to use them and how to implement them in Django.

How do redirects work?

A URL redirect is a type of an HTTP response with a special status code that indicates the requested resource is on another URL location. That way, the client knows where to send the request to retrieve the resource. HTTP redirect can be recognized by a status code starting with 3xx, for example, 301 (Moved Permanently) or 302 (Found). This range of status codes is also known as the redirection status codes (300-399).

You can see how the redirection generally works in the image below.

Django redirect cycle example.

You may ask yourself when redirects are actually used. In modern web development, it’s pretty common to use redirects in various use-cases, for example:

  • When the unauthenticated user tries to open the protected page,
  • When the user successfully signs in,
  • When a form has been filled and successfully submitted,
  • When URL shorteners are used, etc.

As you may notice, the redirection logic greatly depends on the case you are solving, but using Django’s redirect mechanisms in most situations will be enough. 

Temporary and Permanent redirects

Generally, there are two types of redirects you should know about in most cases: temporary and permanent. 

Temporary redirect, represented by the status code 302 (Found), indicates that the requested resource is at the other location at the moment of receiving the request. It means the client will try to resend the request to the other location that was returned as a Location in the HTTP redirect response. 

On the other hand, a permanent redirect indicates that the requested resource has been moved to another location permanently and will never be returned to the original location. Permanent redirects are marked with status code 301 (Moved Permanently). The difference is how the client browser handles this type of redirect. It caches the new location, so it will directly request the resource from the new location next time.

WARNING - Use permanent redirects only if you know what you are doing since it can be pretty hard to make a client browser use the original location again.

How to use the Django redirect?

This section will go through different ways of implementing the URL redirection inside a Django web application, such as using the:

  • HttpResponse with custom parameters,
  • redirect() function,
  • HttpResponseRedirect, and HttpResponsePermanentRedirect classes,
  • RedirectView class-based view
NOTE - The result of using methods listed above is same, but it is good to know different ways of achieving the desired outcome.

Before continuing, let’s assume that the URL configuration inside the urls.py looks like this.

# urls.py
from django.urls import path

from .views import redirect_view, new_url_view

urlpatterns = [
    path('/original-url/', redirect_view)
]

HttpResponse with custom parameters

To return the HTTP response from a Django, you’ll probably want to use the HttpResponse from the django.http module. In this post, you can learn what is and how to use the HttpResponse. Note that the HttpResponse can be configured with different parameters that define the exact type of the HTTP response.

Two parameters need to be configured to define an HTTP redirect successfully. The first one is a status code that needs to be represented by the 3xx code. The second one is the Location header which indicates the location to which the client will need to resend the request.

# views.py
from django.http import HttpResponse

def redirect_view(request):
    response = HttpResponse(status=302)
    response['Location'] = '/new-url/'
    return response

Now if you send the GET request to the /original-url, the HTTP redirect with the 302 status code will be returned, pointing to the /new-url address. This will trigger the client to perform an automatic request directly to the /new-url URL address.

HttpResponseRedirect and HttpResponsePermanentRedirect

To simplify further, Django introduced a few subclasses extending the HttpResponse class. The ones that we need are the HttpResponseRedirect and HttpResponsePermanentRedirect

HttpResponseRedirect overrides the status code to 302, and HttpResponsePermanentRedirect– overrides the status code to 301 – it’s as easy as that.

The usage is also simple; you need to import it from the django.http module and instantiate it with the URL you want to redirect to as the first argument.

# views.py
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect

def redirect_view(request):
    return HttpResponseRedirect('/new-url/')

def permanent_redirect_view(request):
    return HttpResponsePermanentRedirect('/new-url/')

Since hardcoding URLs is not the best practice, you can use the reverse() function from the django.urls module to build a URL. You need to pass the name of the view as the first argument to the function, and Django will take care of correctly building the full URL path.

Let’s assume that you’ve given a name to the /new-url endpoint, like in the example below.

# urls.py
from django.urls import path

from .views import new_url_view

urlpatterns = [
    ...,
    path('/new-url/', new_url_view, name='new-url-location')
]

Now to redirect to the new location successfully you could do it like in the example below.

# views.py
from django.urls import reverse
from django.http import HttpResponseRedirect, HttpResponsePermanentRedirect

def redirect_view(request):
    return HttpResponseRedirect(reverse('new-url-location'))

def permanent_redirect_view(request):
    return HttpResponsePermanentRedirect(reverse('new-url-location'))

redirect() function

Even simpler way to redirect an incoming request is by using the redirect() method provided in the django.shortcuts module. It wraps the functionality of HttpResponseRedirect or HttpResponsePermanentRedirect classes depending on whether the permanent argument is set to True or False.

To define a redirect location, you must pass an argument that can be one of the following:

  • a model instance with the get_absolute_url() method defined,
  • a view name that will be used to reverse-build the URL,
  • an absolute or relative URL

Before diving into examples, let’s assume that the new-url/ address is defined under the view with the name: new-url-location (like in the previous section). Also, in the models.py we have a Book model that implements the get_absolute_url() method.

Let’s see it in action.

from django.urls import reverse
from django.shortcuts import redirect

def model_redirect_view(request):
    book = Book.objects.get(pk=1)
    return redirect(book)

def hardcoded_redirect_view(request):
    return redirect('/new-url/')

def reversed_redirect_view(request):
    return redirect(reverse('new-url-location'))

def permanent_redirect_view(request):
    return redirect(reverse('new-url-location'), permanent=True)

The RedirectView Class-Based View

When the only requirement of a view function is to redirect the user, you can use the django.views.generic.base.RedirectView class-based view. There are various attributes and methods that allow you to configure the RedirectView by your needs:

  • url – URL to which the redirect will be performed.
  • pattern_name – name of a URL pattern to redirect to.
  • permanent – boolean that defines if the redirect is permanent or not.
  • query_string – boolean that defines whether the provided query string will be appended to the redirect URL.
  • get_redirect_url() – method responsible for building the redirect URL. You can implement a custom redirect logic by overwriting it.

To use the RedirectView, you first need to import it from django.views.generic.base module and then subclass it with your own class-based view. In the example below, we subclass the RedirectView with the new ExampleRedirectView view. By setting the url attribute, we tell Django where to redirect the request.

# views.py
from django.views.generic.base import RedirectView

class ExampleRedirectView(RedirectView):
  url = '/new-url/'

In urls.py we need to wire the original URL path to the newly created class-based view so the redirect can be performed. Now when the client sends the request to the original-url/, Django will redirect it to new-url/ URL address.

# urls.py
from django.urls import path
from .views import ExampleRedirectView

urlpatterns = [
    path('/original-url/', ExampleRedirectView.as_view())
]

Summary

There are four different methods of making Django redirect the original request to another location, either by using:

  • the HttpResponse with custom parameters,
  • the HttpResponseRedirect and HttpResponsePermanentRedirect,
  • the redirect() function,
  • Or the RedirectView class-based view

Django uses one of the function-based or class-based redirect views to redirect to a specified URL address. The redirect can be permanent (301 status code) and non-permanent (302 status code.)