Django Class-based views | Decorators, Methods, Template, Redirect view
In this post, we’ll be learning about Django Class-based views | Decorators, Methods, Template and Redirect view.
Table of Contents
- Introduction to Class-based views
- Create a Simple Class-based View
- Example by Snippet
- Class-based views decorators and class methods
- Applying Multiple Decorators to Class-based view method
- Class-based view dispatch() method
- Class-based view TemplateView
- Class-based view RedirectView
- Conclusion
Introduction to Class-based views
The Django Class-based views as an improvement over Function-based views in-terms of code reusability. On request Class-based views returns function corresponds to the request method that will be dispatch and rendered to HTML.
Advantages of using Class-based views
- The Class-based views allow to structure view and return associated function with respect to request method.
- Code reusability is extended by using inheritance.
- The functionality of Class-based views can be improved using mixins,method_decorator or inheriting classes.
- Managing a business login is convenient in Class-based views.
Create a Simple Class-based View
The Class-based view can be created in apps views.py file.
Django provides three base views they are:
- View: To use this you must import from django.views import View
- TemplateView: Used for displaying HTML Template
- RedirectView: For redirecting to another view.
Example
class MyView(View): counter=100 def get(self,request): self.counter+=1 return HttpResponse("counter : {}".format(self.counter))
class MyView
inherits View
which provides basic functionalities of Class-based views.Base View
has only selected/approved method that you could call and they are get
, post
, put
or patch
, delete
.
To add a class-based view in urls.py use with the .as_view()
method this will prepare the class to send callable view in response.
from class_based_views import views urlpatterns = [ path('example-1', views.MyView.as_view(), name='example-1'), ]
Example by Snippet
It takes practise to get used to Class-based views. So we have working example where we create a blog with images and save user who created them.
Let us get started by creating models BlogModel
and BlogFilesModel
which saves a file.
In models.py.
from datetime import datetime from django.db import models from django.contrib.auth.models import User class BlogModel(models.Model): BLOG_STATUS = ( ('PUBLISH', 'Publish'), ('DRAFT', 'Draft'), ) blog_id = models.AutoField(primary_key=True) user = models.ForeignKey( User, on_delete=models.CASCADE, related_name='blogs') title = models.CharField(max_length=255) content = models.TextField(blank=True, null=True) status = models.CharField(max_length=7, choices=BLOG_STATUS) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta(): db_table = 'blogs' verbose_name = 'Blog' verbose_name_plural = 'Blogs' def __str__(self): return self.title def blog_directory_path(instance, filename): return 'uploads/blogs/{}'.format(filename+str(datetime.now())) class BlogFilesModel(models.Model): blog_files_id = models.AutoField(primary_key=True) blog = models.ForeignKey( BlogModel, on_delete=models.CASCADE, related_name='blogs',blank=True) path = models.FileField(blank=False, null=False,upload_to=blog_directory_path) created_at = models.DateTimeField(auto_now_add=True) updated_at = models.DateTimeField(auto_now=True) class Meta(): db_table = 'blog_files' verbose_name = 'Blog' verbose_name_plural = 'Blogs' def __str__(self): return str(self.path)
In views.py.
from django.shortcuts import render, redirect from django.http import HttpResponse from django.views import View from class_based_views.models import BlogModel, BlogFilesModel from django.contrib.auth.models import User import os from django.conf import settings from django.urls import reverse class BlogView(View): template_path = "cbs/simple_view.html" def get(self, request): ctx={ "users" : User.objects.values(), "status" : BlogModel.BLOG_STATUS } return render(request, self.template_path,ctx); def post(self, request): result={} if request.FILES.get("path") is not None: file_list = request.FILES.getlist("path") result = file_upload_interface(request, file_list, dir_path="static/uploads/", allowed_mime_types=[]) id = request.POST.get('blog_id') or None blog, created = BlogModel.objects.update_or_create( pk=id, defaults={ 'user' : User.objects.filter(pk=request.POST["user"]).get(), 'title' : request.POST["title"], 'content' : request.POST["content"], 'status' : "PUBLISH", }) if result.get('files'): for file in result.get('files'): blog.blogs.create(**{ "blog" : blog, "path" : file, }) return redirect(reverse("class_based_views:blog-view-1"))
Now to upload the file we have created function file_upload_interface
this will upload files and return their names. Put this code below BlogView
.
#This function uploads multiple files and returns the name of file def file_upload_interface(request, file_list, dir_path = "uploads/", allowed_mime_types=[]): if not os.path.exists("{}/{}".format(settings.BASE_DIR,dir_path)): os.makedirs("{}/{}".format(settings.BASE_DIR,"/static/uploads"),exist_ok = True) if not isinstance(file_list, list): file_list=list(file_list) directory = os.path.join(settings.BASE_DIR, dir_path) info={ "files" : [] } for file in file_list: file_name= file._name file_mime = file.content_type.split('/')[1] path= "{}{}".format(directory, file_name) is_allowed_to_upload=False #check allowed mime types if that file does not belong to mime type remove it if len(allowed_mime_types) > 0: if file_mime in allowed_mime_types: is_allowed_to_upload=True else: is_allowed_to_upload=True if is_allowed_to_upload is True: with open(path, 'wb+') as destination: for chunk in file.chunks(): destination.write(chunk) info["files"].append(file_name) return info
Now it’s time to create URLs to our BlogView
. Append below code in urls.py file.
from django.urls import path, include from class_based_views import views app_name = 'class_based_views' urlpatterns = [ path('blog-view-1', views.BlogView.as_view(), name='blog-view-1'), ]
We need to create template in-order to store post data to BlogView.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta http-equiv="X-UA-Compatible" content="ie=edge"> <title>Django Class-base views</title> </head> <body> <div> <form action="{% url 'class_based_views:blog-view-1' %}" method="post" enctype="multipart/form-data"> {% csrf_token %} <div> <label for="user" >User</label> <select id="user" name="user" > <option value="">Choose</option> {% for user in users %} <option value="{{user.id}}">{{user.first_name}}</option> {% endfor %} </select> </div> <div> <label for="title" >Blog Title</label> <input type="hidden" id="blog_id" name="blog_id" value="{% firstof blog.id '' %}" > <input type="text" id="title" name="title" value="{% firstof blog.title 'sample title' %}" > </div> <div> <label for="content" >Blog Content</label> <textarea type="text" id="content" name="content">{% firstof blog.content 'sample description' %}</textarea> </div> <div> <label for="status" >Status</label> <select id="status" name="status" > <option value="">Choose</option> {% for a,b in status %} <option value="{{a}}">{{b}}</option> {% endfor %} </select> </div> <div> <label for="path" >Files</label> <input type="file" id="path" name="path" multiple> </div> <div> <input type="submit" value="Submit" > </div> </form> </div> </body> </html>
This is how our final output looks like.
Class-based views decorators and class methods
Just like normal functions, we can add decorators to class methods that we want to run before we call that function.
To use decorators on methods we must import method_decorator
from from django.utils.decorators import method_decorator
.
The method_decorator
takes a function as an argument and returns a callable function. You can add multiple of these decorators one below the other.
def custom_decorator(): def decorator(func): def wrapper(request, *args, **kwargs): print("custom_decorator") return func(request, *args, **kwargs) return wrapper return decorator
The custom_decorator
is a function that will be called before the class-based view method. It has an inner function decorator
which takes a function as an argument and wrapper
function takes request, *args, **kwargs
as argument which belongs to class-based view method.
It is required that decorator must return the callable method after conditional checking or else redirect to another URL.
Django also provides built-in decorators which are login_required, permission_required and never_cache.
Note
The process of applying these decorators is explained below.
Applying Multiple Decorators to method
from django.utils.decorators import method_decorator def custom_decorator(): def decorator(func): def wrapper(request, *args, **kwargs): print("custom_decorator") return func(request, *args, **kwargs) return wrapper return decorator def second_custom_decorator(): def decorator(func): def wrapper(request, *args, **kwargs): print("second_custom_decorator") return func(request, *args, **kwargs) return wrapper return decorator class CustomView(View): @method_decorator(custom_decorator()) @method_decorator(second_custom_decorator()) def get(self,request): return HttpResponse("ok")
Class Methods
In order to return a proper callable function in response, Django class-based views have few classonlymethod as_views().
The as_views()
a method is an entry point for a request-response process. This method binds request object to class and has an inner method view(request, *args, **kwargs)
this method return dispatch()
method which will determine which method must be a triggered for a given request.
If the request method does not match then it returns Method Not Allowed exception.
Note
Some of the available request methods are : get
, post
, put
or patch
, delete
. They are also called approved HTTP list.
The Method as_views()
is called in urls.py file as .as_view().
Class-based view dispatch() method
The dispatch()
method responsible for dispatching right method which corresponds to the request method. The Method Not Allowed with status_code=405 is triggered by HTTP method not available in approved lists.
Class-based view TemplateView
The TemplateView is for the generic purpose where you want to work on a specific view. To use this you have to import TemplateView from from django.views.generic.base import TemplateView
.
This view in proper suited for a static template. But you can also use to pass context data to the template by overriding method get_context_data(self, **kwargs)
.
Real-Life Example
In views.py.
from django.views.generic.base import TemplateView class HomeView(TemplateView): template_name = "cbs/home.html" def get_context_data(self, **kwargs): context = super(HomeView,self).get_context_data(**kwargs); context["blogs"] = BlogModel.objects.all() return context
In template/cbs/home.html.
<div> <h1 style="text-align: center;" >Welcome to Home</h1> <div> <h3 style="text-align: center;" >Blog List</h3> <table border="1" style="width: 40%;border-collapse:collapse;"> <thead> <tr> <th>User</th> <th>Title</th> <th>Status</th> </tr> </thead> <tbody> {% for blog in blogs %} <tr> <td>{{blog.user.first_name}} {{blog.user.last_name}}</td> <td>{{blog.title}}</td> <td>{{blog.status}}</td> </tr> {% endfor %} </tbody> </table> </div> </div>
This is how our final output looks like.
Class-based view RedirectView
The Django RedirectView is used to redirect to external or internal URL. This view inherits Base View.
The RedirectView view provides a convenient way to redirect to 301 permanent and 302 temporary URL.
To uses this view import RedirectView from from django.views.generic.base import RedirectView
.
Attributes
- permanent: If set to True than redirects with 301 permanent redirect else with 302 temporary redirects.
- URL: Specify the URL to redirect. example: home-page.
- pattern_name: You can specify URL name and it implicitly adds it to reverse() function. example : class_based_views:home-page.
- query_string: If set to True redirects with a query string. Get query string from
request.META.get('QUERY_STRING', '')
.
Example
In views.py.
from django.views.generic.base import RedirectView class HomeRedirectView(RedirectView): permanent = False url = None pattern_name = 'class_based_views:home-page' query_string = True
In urls.py.
app_name = 'class_based_views' urlpatterns = [ path('home-page', views.HomeView.as_view(), name='home-page'), path('home-redirect', views.HomeRedirectView.as_view(), name='home-redirect'), ]
You can visit Django official docs section here here
Conclusion
So we have come to the conclusion part of our Django Class-based views | Decorators, Methods, Template and Redirect view post. If you like this then please share and for queries comment below. We’ll reach to you soon.
Related Posts
- Django Querysets | One To One Foreign Key, Inner Joins, Query Filtering
- Django Queryset select_related | Boosting Query Performance




