Skip to content

Django - Generic Views

Writing views can sometimes involve repetitive boilerplate code, especially for common tasks like displaying a list of objects, showing details for one object, or handling simple forms. Django’s generic views (which are class-based views, or CBVs) provide pre-built solutions for these common patterns, allowing you to write less code.

Generic views are Python classes found in django.views.generic. You typically use them either directly in your URLconf or by subclassing them in your views.py file to customize their behavior.

  • Display Views:
  • TemplateView: Renders a given template with optional context.
  • ListView: Renders a list of objects (usually from a database query).
  • DetailView: Renders details for a single object.
  • Editing Views:
  • FormView: Renders and processes a form.
  • CreateView: Displays a form for creating a new object and handles saving it.
  • UpdateView: Displays a form for editing an existing object and handles saving it.
  • DeleteView: Displays a confirmation page and handles deleting an existing object.
  • Date-Based Views: (ArchiveIndexView, YearArchiveView, MonthArchiveView, etc.) for displaying objects based on dates.

Example 1: Displaying a Static Page (TemplateView)

Section titled “Example 1: Displaying a Static Page (TemplateView)”

Imagine you have a simple about.html template you want to display.

Method 1: Directly in urls.py

myapp/urls.py
from django.urls import path
from django.views.generic import TemplateView
urlpatterns = [
path('about/',
TemplateView.as_view(template_name='myapp/about.html'),
name='about'),
# ... other URLs
]

Method 2: Subclassing in views.py (useful if you need to add extra context)

myapp/views.py
from django.views.generic import TemplateView
class AboutView(TemplateView):
template_name = 'myapp/about.html'
# Optional: Add extra context data
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['page_title'] = 'About Us'
return context
myapp/urls.py
from django.urls import path
from .views import AboutView
urlpatterns = [
path('about/', AboutView.as_view(), name='about'),
# ... other URLs
]

In both cases, accessing /myapp/about/ will render the myapp/templates/myapp/about.html template.

Let’s list all entries from a hypothetical Article model.

# myapp/models.py (Hypothetical)
from django.db import models
from django.urls import reverse
class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
pub_date = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
def get_absolute_url(self):
return reverse('article_detail', kwargs={'pk': self.pk})

Using ListView:

myapp/views.py
from django.views.generic import ListView
from .models import Article
class ArticleListView(ListView):
model = Article # Specify the model to list
template_name = 'myapp/article_list.html' # Optional: Defaults to myapp/article_list.html
context_object_name = 'articles' # Optional: Name in template context (default: object_list)
ordering = ['-pub_date'] # Optional: Order the results
paginate_by = 5 # Optional: Enable pagination
myapp/urls.py
from django.urls import path
from .views import ArticleListView
urlpatterns = [
path('articles/', ArticleListView.as_view(), name='article_list'),
# ... other URLs like article_detail
]

Template (myapp/templates/myapp/article_list.html):

myapp/templates/myapp/article_list.html
<h1>Articles</h1>
<ul>
{% for article in articles %} {# Use context_object_name here #}
<li>
<a href="{{ article.get_absolute_url }}">{{ article.title }}</a>
(Published: {{ article.pub_date|date:"Y-m-d" }})
</li>
{% empty %}
<li>No articles have been published yet.</li>
{% endfor %}
</ul>
{# Add pagination controls if using paginate_by #}
{% if is_paginated %}
<div class="pagination">
<span class="step-links">
{% if page_obj.has_previous %}
<a href="?page=1">&laquo; first</a>
<a href="?page={{ page_obj.previous_page_number }}">previous</a>
{% endif %}
<span class="current">
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">next</a>
<a href="?page={{ page_obj.paginator.num_pages }}">last &raquo;</a>
{% endif %}
</span>
</div>
{% endif %}

Accessing /myapp/articles/ will display a paginated list of articles, ordered by publication date.

Generic views significantly reduce the amount of code needed for common tasks, promoting DRY principles and faster development. Refer to the Django documentation on Class-Based Views for more details and customization options.