The Complete Guide to Django Redirects

When developing a web application, sometimes it is necessary to redirect users to a different part of the application or a third party location. This can be achieved through HTTP URL redirects. basic functionality of an HTTP URL Redirect is to control the flow of your web application, ensuring that each user interaction is pointed towards the desired location. The Django framework offers built-in support for HTTP URL Redirects.

Table of Contents

You can skip to a specific section of this Django redirect tutorial using the table of contents below:

Basics of HTTP URL Redirection

When a request is made through a web browser, it will initiate a GET request to fetch the data from the requested URL. Each request will receive a response from the corresponding server containing an HTTP status code, headers, and finally the content. The important thing here is the status code from which we can ascertain the status of the application or the server. The HTTP 200 indicates a successful connection to 401 authorization errors and so on. You can get a complete overview of each status code by referring to the MWD Web Docs.

Redirects differ from a normal HTTP request due to the following factors.

The redirect will return a 302 HTTP status code which indicates that the redirect URL was found. (The HTTP response codes in the 300-399 range are dedicated for Redirect requests). Additionally, a redirect request will contain the Location header with the relative URL and indicate a Content-Length of zero since there is an empty body in the response.

Basic Django Redirection

The Django Framework offers tailor-made functions to accommodate redirect requests. Those are the HTTPSResponseRedirect Class and the redirect function.

HTTPSResponseRedirect Class

This subclass of HTTPResponse class is one of the methods available for redirects. You can define the redirect URL by calling the HTTPResponseRedirect method with the URL as an argument. This functionality can be illustrated as follows.

def index(request):
    return HttpResponseRedirect("<Redirect URL>")

The above code will return a redirect object with the appropriate status code (302), headers, and redirect to the desired location. One of the major limitations of this method is that all the URLs are hardcoded and can not be configured dynamically.

Django redirect() Function

The Django shortcut function redirect() provides a complete solution to deal with many kinds of redirect requests and create dynamic redirect URLs. The redirect() function can redirect users to models, other URLs and can also be used to pass key values and any other required information.

Let’s go through the following code-blocks to get an idea about different types of redirects which can be configured using the redirect function.

Calling a Django Model.

This will call the getabsoluteurl() method of the given object. If no getabsoluteurl() method is available in the object, Django will raise a TypeError.

from django.shortcuts import redirect
from bookshop.models import Books
 
def redirect_to_book(request, requested_book_id):
    book_search = Books.objects.get(book_id=requested_book_id)
    return redirect(book_search)
    # return HttpResponseRedirect(book_search.get_absolute_url())

Calling a URL by accepting View Arguments

The redirect() function will try to reverse a URL using the provided arguments.

from django.shortcuts import redirect
from bookshop.models import Books
 
def redirect_to_book(request, requested_book_id):
    return redirect("book_details", book_id=requested_book_id)
    # return HttpResponseRedirect(reverse("book_details", args=(requested_book_id, )))

Calling a Static URL

Similar to the HTTPResponseRedirect, you can specify an absolute or a relative URL. Any string containing a forward slash (/) or a period (.) will be identified as a URL by the redirect() function.

from django.shortcuts import redirect
 
# Relative URL
def redirect_to_book(request):
    return redirect("/book_details/author")
    # return HttpResponseRedirect("/book_details/author")
 
# Absolute URL
def redirect_to_book(request):
    return redirect("https://www.bookshop.com/book_details/author")
    # return HttpResponseRedirect("https://www.bookshop.com/book_details/author")

Temporary and Permanent Redirects

There are two types of HTTP redirects called temporary redirects and permanent redirects. A redirect with an HTTP 302 Found response is a temporary redirect while a redirect with an HTTP 301 Permanent response is considered a permanent redirect.

You can use a temporary redirect to temporarily redirect a user in scenarios such as redirecting a user to a new application location, controlling the user interaction flow, directing to a landing page while in maintenance, etc… A permanent redirect can be used if the URL which the user is trying to access is permanently moved to a different location. When a web application is moved to a new URL, you can create a permanent redirect from the old URL to point to the new URL. However, a permanent redirect will cache the redirect response in the browser and directly route the traffic to the cached address without checking the redirect URL again.

In the Django framework, you can define permanent redirects as follows.

HTTPResponse Class

from django.http import  HttpResponsePermanentRedirect
 
def index(request):
    return HttpResponsePermanentRedirect("<Redirect URL>")

redirect() Function

from django.shortcuts import redirect
 
def index(request):
    return redirect('<Redirect URL>', permanent=True)

Both types of redirects are crucial components in Search Engine Optimization and User Experience Improvements.

Django Redirect Limitations

The Django redirects have two major limitations.

Empty Redirect The functionality of the redirect() function is to return a redirect response object which carries out the redirect. Because of that, there must always be a response object defined in the Django application views or middleware. Otherwise, no redirect will happen.

Infinite Redirect Loops When two redirect functions are pointing towards each other, it will create an infinite redirect loop which may lead to unprecedented functionality loss in applications. Therefore, developers should be vigilant not to configure a redirect flow that points towards each other.

Configuring a Simple Django Redirection Application

Let's create a simple Django app called the bookshop with a model containing book details and author details and a view to display a list of books, search books by the id, and an external link to buy the books.

Create the Models

The below code creates the application model containing the Book and Author models. This will be the base of our data set.

models.py

from django.db import models
from django.core.validators import DecimalValidator
 
class Book(models.Model):
    book_id = models.CharField(primary_key=True, max_length=30)
    name = models.CharField(max_length=250)
    description = models.TextField(blank=True, null=True)
    author = models.ForeignKey('Author', verbose_name='Authors', on_delete=models.PROTECT)
    price = models.DecimalField(max_digits=4,null=False,decimal_places=2, validators=[DecimalValidator(10, 2)])
 
    class Meta:
        verbose_name_plural = "Books"
        db_table = "Books"
        ordering = ["name"]
 
    def __str__(self):
        return f"{self.name}"
 
class Author(models.Model):
    first_name = models.CharField(max_length=100)
    middle_name = models.CharField(max_length=100, blank=True, null=True)
    last_name = models.CharField(max_length=150)
    email = models.EmailField(max_length=150)
 
    class Meta:
        verbose_name_plural = "Authors"
        db_table = "Authors"
        ordering = ["first_name", "last_name"]
 
    def __str__(self):
        return f"{self.first_name} {self.last_name}"

Create a Form

The following code-block will create a single field form to enter the Book ID.

from django import forms
 
class BookForm(forms.Form):
    book_id = forms.CharField(label="Book ID", max_length =250)

HTML Templates

Each view will contain a custom template to display the data.

BookList.html

<h1>Book List</h1>
 
{% for book in books %}
    <li>{{book.name}} - {{book.author}}</li><br>
{% endfor %}

BookDetails.html

<h1>Book Details</h1>
 
<hr/>
<table style="width:100%">
    <tr>
      <td><b>Title</b></td>
      <td>{{book.name}}</td>
    </tr>
    <tr>
      <td><b>Author</b></td>
      <td>{{book.author}}</td>
    </tr>
    <tr>
      <td valign="top"><b>Description</b></td>
      <td>{{book.description}}</td>
    </tr>
    <tr>
      <td><b>Price</b></td>
      <td>{{book.price}}</td>
    </tr>
  </table>
<hr/>

BookSearch.html

<form method ='post'>
    {% csrf_token %}
    {{form.as_p}}
    <input type="submit" value = "Submit">
</form>

Creating the Views

The most important part of creating redirects is the views section. In the following code-block, multiple views are defined.

  • BookViewAll - Simple request to obtain a list of books using the BookList template.
  • BookView - Get details of a single book by the given book id. The output will be displayed using the BookDetails template.
  • SeachView - The first redirection view. In this function, you will be calling the BookForm and request user input. After the user input, the user will be redirected to the BookView function to obtain the details. This can be considered as an internal redirect to control the user flow while passing a variable with the redirect.
  • ExternalShop - The last view in which the user will be redirected to an external website.

views.py

from django.shortcuts import render
from django.shortcuts import redirect
from bookshop.models import Book
from bookshop.forms import BookForm
 
# Obtain a List of All the Books
def BookViewAll(request):
    book_details = Book.objects.all()
    context = {
        "books": book_details
    }
    return render(request,"bookshop/BookList.html", context)
 
# Get Details of a Book
def BookView(request, id):
    get_details = Book.objects.get(book_id=id)
    context = {
        "book": get_details
    }
    return render(request,"bookshop/BookDetail.html", context)
 
# Redirect to another View
def SearchView(request):
    if request.method == "POST":
        form = BookForm(request.POST)
        if form.is_valid():
            book_id = form.cleaned_data["book_id"]
            # Redirecting to the BookView
            return redirect("BookView", id=book_id)
    else:
        form = BookForm()
        context ={
            "form":form,
        }
        return render(request, "bookshop/BookSearch.html", context)   
 
# Redirect to external URL
def ExternalShop(request):
    return redirect("https://www.bookdepository.com")

Setting up URL Patterns

In the previous section, You have configured the redirects using the views. However, still, there's no internal path for any of these views. You can define internal paths using the urlpatterns in the urls.py file of the main project.

urls.py

from bookshop.views import BookView, BookViewAll, SearchView, ExternalShop
from django.contrib import admin
from django.urls import path
 
urlpatterns = [
    path('admin/', admin.site.urls),
    # Path to Book Details
    path('book/<str:id>', view=BookView, name="BookView"),
    # Path to Obtain a List of Books
    path('booklist/', view=BookViewAll, name="BookViewAll"),
    # Path to Search Function - Internal Redirection
    path('books/search', view=SearchView, name="SearchView"),
    # Path to External Redirection
    path('externalbuy/', view=ExternalShop, name="ExternalShop"),
]

Now, perform the migrations and start the Django server and you are all set to explore the redirection functionality.

Testing Simple Redirections

First, let us identify a non-redirection request by visiting the booklist URL to get a list of books.

http://127.0.0.1:8000/booklist/

Since the above is a normal HTTP GET request, it will result in an HTTP 200 response indicating a direct request. You can check this using the Django development server logs in the terminal.

USER -> Book List URL

Next, you can use the search function of the application to demonstrate an internal redirection. Navigate to the search URL, fill in the details and click on submit and then it will redirect the user from the SearchView to the BookView of the application.

http://127.0.0.1:8000/books/search

http://127.0.0.1:8000/book/BK02009

Using the terminal, you can observe the behaviour of this redirection. The user first visited the search page and then got redirected to a different internal Django view. The HTTP 302 status code indicated this redirection. In this instance, a POST request will be used in the redirection step as you are submitting the search query to the application.

USER -> Search URL -> Book Details URL (Redirected at form submission)

External URL redirections behave in the same way as internal redirections. The only difference is that instead of an internal location, you will specify a fully qualified domain name to direct the user to an external website. Visiting the following URL will redirect the user to the specified external website.

http://127.0.0.1:8000/externalbuy

By checking the terminal output, you can see that a successful redirection has happened when requesting the above URL.

You can also convert the above URL to a permanent redirection by adding the permanent parameter to the ExternalShop view as shown below.

def ExternalShop(request):
    return redirect("https://www.bookdepository.com", permanent=True)

The above modification will create a permanent redirection and you can verify it by checking the terminal output of the Django server. It will indicate an HTTP 301 permanent response, confirming the update as a permanent redirect.

RedirectView Class

Django provides a special RedirectView class when the only requirement of a view function is to redirect the user. This class provides the necessary options to create dynamic redirects. Following are the most commonly used class attributes to create redirect URLs.

  • .url - Defines the redirect URL as a string and expands any string formatting using arguments passed in the view.
  • .pattern_name - Defines the name of the URL pattern to be redirected to.
  • .permanent - This attribute will use boolean true or false values to determine the permanence of a redirect.
  • .query_string - Using true or false values, this attribute will add or append a provided query string to the redirect URL.
  • getredirecturl(*args, **kwargs) - The base method which is used in the class to generate the redirect URL. This will return the URL in a string format. The main advantage of this function is that the Django framework allows developers to overwrite this method to meet their requirements...

Django provides two methods of using RedirectView class. One is defining a redirect using both urls.py and views.py and the other is simply invoking the RedirectView class directly using the urls.py file.

Let’s create a redirect to search the external site (bookdespository.com) using RedirectView. You can modify your web application to include that redirect as follows.

view.py

# Import the RedirectView
from django.views.generic.base import RedirectView
 
'''
Previous Functions
'''
# New Class for External Search
class ExternalSearch(RedirectView):
    url = "https://www.bookdepository.com/search?searchTerm=harry+potter&search=Find+book"

urls.py

from bookshop.views import BookView, BookViewAll, SearchView, ExternalShop, ExternalSearch
from django.contrib import admin
from django.urls import path
 
urlpatterns = [
    '''
    Previous urlpatterns
    '''
    # Path to Redirect Class
    path('externalsearch/', view=ExternalSearch.as_view())
]

Using the url attribute of the ExternalSearch Class, a redirect URL will be created and the user will be redirected to the external website.

This will be reflected as a normal redirect in the Django server terminal.

You can simplify the above use case by defining the URL directly as a keyword argument within the as_view() function in the urls.py file of the urlpatterns section.

urls.py

from django.views.generic.base import RedirectView
from bookshop.views import BookView, BookViewAll, SearchView, ExternalShop
from django.contrib import admin
from django.urls import path
 
urlpatterns = [
    '''
    Previous urlpatterns
    '''
 
    # Path to Redirect Class with Keyword Argument
    path('externalsearch/', 
    view=RedirectView.as_view(url="https://www.bookdepository.com/search?searchTerm=harry+potter&search=Find+book"))
]

Final Thoughts

In this article, you learned about Django redirects. You could also get a thorough knowledge of the importance of using redirects and how to use them in applications by referring to this article. Django provides inbuilt support for creating and customizing redirects to fulfil developer requirements. Redirects can be used to enhance the user experience as well as to integrate with third-party applications or websites to provide users with additional functionality.

If you enjoyed this article, be sure to join my Developer Monthly newsletter, where I send out the latest news from the world of Python and JavaScript:


Written on January 15th, 2021