django class based generic views

django built-in template tags

In web application development, it's possible to have a repeated patterns again and again. so, Django comes with solution. The solution is generic class based views.

Advantanges of generic class based views

  • Django’s generic views were developed to ease that pain.
  • Generic views abstracted the common functionality so, we can write less code and get the functionality done quickly.
  • We can inherit the generic views and extend the functionality so that we can speed up the development.
  • Code will be clean and well organized

Disadvantages of generic class based views

  • It looks some what difficult when compare to function based views because of the abstraction of the functionality provided by the class based views.
  • It will be difficult to understand the code when you didn't know OOP's concepts atleast the inheritance concept.

Generic views

We have the following views provided by django

  • View
  • TemplateView
  • FormView
  • CreateView
  • DetailView
  • ListView
  • UpdateView
  • DeleteView

Note: Django also provides other class based views but these are used frequently.

Base class - View

  • It's the base class for all generic views.
  • We need to implement the HTTP request methods
  • as_view is the class method which returns the view.

Let's see an example view to return simple HTTP response

views.py

from django.views.generic import View
from django.http import HttpResponse

class SimpleView(View):
  def get(self, request):
    return HttpResponse("Hello")

urls.py

from django.urls import path
from .views import SimpleView

urlpatterns = [
  path("simple-view/", SimpleView.as_view(), name="simple")    
]

Generic TemplateView

  • It's used to render the template with context
  • It inherits the base class View
  • We just need to provide the template path to render the template with attribute teamplate_name.
  • We can pass the context to template by method get_context_data

Let's see an example to terms page

terms.html

<html>
  <body>
    <h1>Hello, {{user}}</h1>
  </body>
</html>

views.py

from django.views.generic import TemplateView

class TermsView(TemplateView):
  template_name = "terms.html"

  def get_context_data(self, *args, **kwargs):
    context = {
      "user": "Anji"
    }
    return context

urls.py

from django.urls import path
from .views import TermsView

urlpatterns = [
  path("terms/", TermsView.as_view(), name="terms")    
]

Generic FormView

  • It's used to collect the input from the user.
  • we need to inherit the FormView to the current view to implement it.
  • It takes attributes form_class, template_name and success_url
  • form_valid method is to write our business logic. It's called when form is valid.

Let's see an example

forms.py

from django import forms

class CityForm(forms.Form):
    name = forms.CharField()
    description = forms.CharField(widget=forms.Textarea)

city_form.html

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

views.py

from django.views.generic.edit import FormView
from .forms import CityForm

class CityFormView(FormView):
  form_class = CityForm
  template_name = "city_form.html"
  success_url ="/thanks/"

  def form_valid(self, form):
    # our business logic here
    return super().form_valid(form)

urls.py

from django.urls import path
from .views import CityFormView

urlpatterns = [
  path("terms/", CityFormView.as_view(), name="city_form")    
]

Generic CreateView

  • It's used to create an instance of a table in the database.
  • Organization of code related to specific HTTP methods (GET, POST, etc.) can be addressed by separate methods instead of conditional branching.

usecase: Let's write a code to add the city details to the city table.

models.py

from django.db import models

class City(models.Model):
    title = models.CharField(max_length = 200)
    description = models.TextField()

    def __str__(self):
        return self.title

city_form.html

<form method="POST" enctype="multipart/form-data">

    <!-- Security token -->
    {% csrf_token %}

    <!-- Using the formset -->
    {{ form.as_p }}

    <input type="submit" value="Submit">
</form>

views.py

from django.views.generic.edit import CreateView
from .models import City

class CityCreateView(CreateView):
  model = City
  fields = ['title', 'description']
  template_name = "city_form.html"

urls.py

from django.urls import path
from .views import CityView

urlpatterns = [
  path('city', CityCreateView.as_view(), name="city-create"),
]

Like, above we can write create functionality with very minimal code. This is how django class based views comes in to handy.

Generic DetailView

  • It's used to retrive the instance from the database and show the info to the user.
  • It requires minimal effort to implement it with generic CBV(i.e class based views) views.
  • Let's use the same model City from CreateView example.
  • It sends model instance as object to template context
  • It uses pk url kwarg to find the correct model instance in the database table.

Let's see an example implementation

city_detail.html

<h1>{{ object.title }}</h1>
<p>{{ object.description }}</p>

views.py

from django.views.generic.detail import DetailView
from .models import City

class CityDetailView(DetailView):
  model = City
  template_name = "city_detail.html"

urls.py

from django.urls import path
from .views import CityDetailView

urlpatterns = [
  path('city/<pk>/', CityDetailView.as_view(), name="city-detail"),
]

It's that simple to implement the django generic detail view.

Generic ListView

  • It's used to list/show all objects/rows in the database table to user.
  • It comes with pagination as it's difficult to handle large data.
  • It sends all objects or paginated objects to template context with name object_list

Let's see an example

city_list.html

<ul>
    <!-- Iterate over object_list -->
    {% for object in object_list %}
    <!-- Display Objects -->
    <li>{{ object.title }}</li>
    <li>{{ object.description }}</li>

    <hr/>
    <!-- If objet_list is empty  -->
    {% empty %}
    <li>No objects yet.</li>
    {% endfor %}
</ul>

views.py

from django.views.generic.list import ListView
from .models import City

class CityListView(ListView):
  model = City

urls.py

from django.urls import path
from .views import CityListView

urlpatterns = [
  path('all-cities/', CityListView.as_view(), name="city-list"),
]

It's that simple to implement the generic class based listview in django.

Generic UpdateView

  • It's used to update the existing object/row in the database table.
  • It automatically generates the form from the model and sends to the template context
  • It can be accessed with name form in the template
  • It identifies the object with url kwarg pk

Let's see an example

city_update.html

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

views.py

from django.views.generic.edit import UpdateView
from .models import City

class CityUpdateView(UpdateView):
  model = City
  fields = ["title","description"]
  success_url ="/"

urls.py

from django.urls import path
from .views import CityUpdateView

urlpatterns = [
  path('city/<pk>/update', CityUpdateView.as_view(), name="city-update"),
]

That's how we implement the update view with class based UpdateView in django.

Generic DeleteView

  • It's used to remove/delete an instance from the database table.
  • DeleteView identifies the correct instance with the url kwarg pk

Let's see an example

city_delete.html

<form method="post">
  {% csrf_token %}     
  <p>Are you sure you want to delete "{{ object }}"?</p>
  <input type="submit" value="Confirm">
</form>

views.py

from django.views.generic.edit import DeleteView
from .models import City

class CityDeleteView(DeleteView):
    model = City
    success_url ="/"

urls.py

from django.urls import path
from .views import CityDeleteView

urlpatterns = [
    path('city/<pk>/delete/', CityDeleteView.as_view(), name="city-delete"),
]

We have seen simple examples to use class based views in django. Create a djano app and try it out.

Reference: https://docs.djangoproject.com/en/3.2/topics/class-based-views/generic-display/