Introduction to Django Class-Based Views

This article introduces Django’s class-based views and explains how they organize request-handling logic using Python classes. It covers the base View class, HTTP method handlers, generic views, URL configuration, common attributes and methods, mixins, CRUD patterns, and situations where class-based views are preferable to function-based views.

Introduction to Django Class-Based Views

Django views receive web requests and return web responses.

A view might render an HTML template, process a form, redirect the user, return JSON, or retrieve data from the database.

Django supports two main styles of views:

  • function-based views
  • class-based views

A function-based view is written as a Python function:

python

1
2
3
4
5
from django.shortcuts import render


def article_list(request):
    return render(request, "articles/article_list.html")

A class-based view is written as a Python class:

python

1
2
3
4
5
6
7
from django.views import View
from django.shortcuts import render


class ArticleListView(View):
    def get(self, request):
        return render(request, "articles/article_list.html")

Both examples can produce the same response.

The difference is how the code is structured.

Class-based views organize request-handling behavior into classes and methods. They also make it possible to reuse common view logic through inheritance, mixins, and Django’s built-in generic views.

What Is a Class-Based View?

A class-based view is a Python class that handles HTTP requests.

Instead of checking the request method manually, a class-based view usually defines methods such as:

text

1
2
3
4
5
get()
post()
put()
patch()
delete()

Django calls the method that matches the incoming HTTP request.

For example:

python

1
2
3
4
5
6
7
from django.http import HttpResponse
from django.views import View


class GreetingView(View):
    def get(self, request):
        return HttpResponse("Hello from a class-based view.")

When the browser sends a GET request, Django calls the view’s get() method.

A class-based view must be converted into a callable view before it can be used in a URL pattern.

This is done with as_view():

python

1
2
3
4
5
6
7
8
from django.urls import path

from .views import GreetingView


urlpatterns = [
    path("greeting/", GreetingView.as_view(), name="greeting"),
]

The important part is:

python

1
GreetingView.as_view()

Do not pass the class directly:

python

1
path("greeting/", GreetingView, name="greeting")  # Incorrect

Why Use Class-Based Views?

Class-based views can reduce repeated code and provide a predictable structure for common request patterns.

They are especially useful when several views perform similar operations.

Common examples include:

  • displaying a list of objects
  • displaying one object
  • creating a record
  • updating a record
  • deleting a record
  • handling both GET and POST requests
  • applying reusable authentication or permission logic

Django includes generic class-based views for many of these tasks.

For example, a list page can often be written with only a few lines:

python

1
2
3
4
5
6
7
from django.views.generic import ListView

from .models import Article


class ArticleListView(ListView):
    model = Article

Django can use this declaration to:

  • query all Article objects
  • choose a default template name
  • provide the objects to the template
  • return the rendered response

This removes much of the repeated code found in ordinary list views.

Function-Based Views and Class-Based Views

A function-based view places the request-handling logic inside a function.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
from django.shortcuts import render

from .models import Article


def article_list(request):
    articles = Article.objects.all()

    return render(
        request,
        "articles/article_list.html",
        {"articles": articles},
    )

The equivalent class-based view could be:

python

1
2
3
4
5
6
7
8
9
from django.views.generic import ListView

from .models import Article


class ArticleListView(ListView):
    model = Article
    template_name = "articles/article_list.html"
    context_object_name = "articles"

Neither style is always better.

Function-based views are often easier when:

  • the view is small
  • the request flow is unusual
  • the logic does not match a generic pattern
  • direct control is more important than reuse

Class-based views are often useful when:

  • the view follows a common pattern
  • several views share behavior
  • HTTP methods need separate handlers
  • built-in generic views remove repeated code
  • mixins can provide reusable functionality

The best choice depends on the complexity and structure of the view.

The Base View Class

The simplest class-based view inherits from django.views.View.

python

1
from django.views import View

The class can define methods for supported HTTP request types.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.http import HttpResponse
from django.views import View


class ExampleView(View):
    def get(self, request):
        return HttpResponse("This is a GET response.")

    def post(self, request):
        return HttpResponse("This is a POST response.")

A GET request calls:

python

1
get()

A POST request calls:

python

1
post()

This gives each request method its own section of code.

Handling GET Requests

A GET request is normally used to retrieve or display information.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
from django.shortcuts import render
from django.views import View

from .models import Article


class ArticleListView(View):
    def get(self, request):
        articles = Article.objects.all()

        return render(
            request,
            "articles/article_list.html",
            {"articles": articles},
        )

This view:

  1. receives a GET request
  2. retrieves all articles
  3. renders a template
  4. passes the articles into the template context

The URL pattern is:

python

1
2
3
4
5
6
7
8
from django.urls import path

from .views import ArticleListView


urlpatterns = [
    path("articles/", ArticleListView.as_view(), name="article-list"),
]

Handling POST Requests

A POST request is normally used to submit or change data.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
from django.shortcuts import redirect, render
from django.views import View

from .forms import ArticleForm


class ArticleCreateView(View):
    def get(self, request):
        form = ArticleForm()

        return render(
            request,
            "articles/article_form.html",
            {"form": form},
        )

    def post(self, request):
        form = ArticleForm(request.POST)

        if form.is_valid():
            form.save()
            return redirect("article-list")

        return render(
            request,
            "articles/article_form.html",
            {"form": form},
        )

The get() method displays an empty form.

The post() method:

  1. receives submitted data
  2. validates the form
  3. saves a valid article
  4. redirects the user
  5. redisplays invalid forms with errors

Separating GET and POST behavior into different methods can make the request flow easier to follow.

Using URL Parameters

Class-based views can receive values captured from the URL.

Suppose the URL includes an article ID:

python

1
2
3
4
5
path(
    "articles/<int:article_id>/",
    ArticleDetailView.as_view(),
    name="article-detail",
)

The value is passed to the view method as a keyword argument:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
from django.shortcuts import get_object_or_404, render
from django.views import View

from .models import Article


class ArticleDetailView(View):
    def get(self, request, article_id):
        article = get_object_or_404(
            Article,
            id=article_id,
        )

        return render(
            request,
            "articles/article_detail.html",
            {"article": article},
        )

The captured value can also be accessed through:

python

1
self.kwargs

For example:

python

1
article_id = self.kwargs["article_id"]

The as_view() Method

Django’s URL system expects a callable object.

A class itself is not the final callable view, so Django provides as_view().

python

1
ArticleListView.as_view()

The as_view() method creates a callable that:

  1. receives the request
  2. creates an instance of the view class
  3. stores request information on that instance
  4. determines the HTTP request method
  5. calls the matching method, such as get() or post()
  6. returns the response

This is why the class-based view is registered like this:

python

1
2
3
4
5
path(
    "articles/",
    ArticleListView.as_view(),
    name="article-list",
)

Useful View Attributes

A class-based view instance has several useful attributes.

self.request

Contains the current request object.

python

1
user = self.request.user

self.args

Contains positional arguments passed from the URL.

python

1
value = self.args[0]

Keyword URL arguments are more common in modern Django projects.

self.kwargs

Contains named values captured from the URL.

python

1
article_id = self.kwargs["article_id"]

These attributes are available after Django initializes the view.

Generic Class-Based Views

Django provides built-in class-based views for common web application patterns.

These are called generic class-based views.

Common generic views include:

View Purpose
TemplateView Render a template
RedirectView Redirect to another URL
ListView Display a list of objects
DetailView Display one object
CreateView Create an object
UpdateView Update an object
DeleteView Delete an object
FormView Display and process a form

These views provide common behavior that can be configured with class attributes or overridden methods.

TemplateView

TemplateView renders a template.

python

1
2
3
4
5
from django.views.generic import TemplateView


class AboutView(TemplateView):
    template_name = "pages/about.html"

URL pattern:

python

1
path("about/", AboutView.as_view(), name="about")

This is useful for mostly static pages.

Adding Template Context

Override get_context_data() to add data:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.views.generic import TemplateView


class AboutView(TemplateView):
    template_name = "pages/about.html"

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["page_title"] = "About Us"
        return context

The template can access:

django

1
{{ page_title }}

Always call:

python

1
super().get_context_data(**kwargs)

This preserves the context created by the parent class.

ListView

ListView displays a collection of objects.

python

1
2
3
4
5
6
7
from django.views.generic import ListView

from .models import Article


class ArticleListView(ListView):
    model = Article

By default, Django looks for a template named:

text

1
articles/article_list.html

The pattern is:

text

1
<app_label>/<model_name>_list.html

The default context variable is:

text

1
object_list

The template can use:

django

1
2
3
{% for article in object_list %}
    <h2>{{ article.title }}</h2>
{% endfor %}

Customizing the Template and Context Name

python

1
2
3
4
class ArticleListView(ListView):
    model = Article
    template_name = "articles/list.html"
    context_object_name = "articles"

The template can now use:

django

1
2
3
{% for article in articles %}
    <h2>{{ article.title }}</h2>
{% endfor %}

Customizing the Queryset

Override get_queryset():

python

1
2
3
4
5
6
7
8
9
class ArticleListView(ListView):
    model = Article
    template_name = "articles/article_list.html"
    context_object_name = "articles"

    def get_queryset(self):
        return Article.objects.filter(
            is_published=True,
        ).order_by("-published_at")

This is useful for:

  • filtering records
  • ordering results
  • limiting results
  • filtering by the current user
  • using URL values in a query

For example:

python

1
2
3
4
def get_queryset(self):
    return Article.objects.filter(
        author=self.request.user,
    )

DetailView

DetailView displays one object.

python

1
2
3
4
5
6
7
from django.views.generic import DetailView

from .models import Article


class ArticleDetailView(DetailView):
    model = Article

A common URL pattern is:

python

1
2
3
4
5
path(
    "articles/<int:pk>/",
    ArticleDetailView.as_view(),
    name="article-detail",
)

By default, Django looks for:

text

1
articles/article_detail.html

The object is available as:

text

1
object

It may also be available using the model name:

text

1
article

Example template:

django

1
2
3
<h1>{{ article.title }}</h1>

<p>{{ article.content }}</p>

Using a Slug

A detail view can retrieve an object by slug:

python

1
2
3
4
class ArticleDetailView(DetailView):
    model = Article
    slug_field = "slug"
    slug_url_kwarg = "slug"

URL pattern:

python

1
2
3
4
5
path(
    "articles/<slug:slug>/",
    ArticleDetailView.as_view(),
    name="article-detail",
)

CreateView

CreateView displays a form and creates a new model object.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.urls import reverse_lazy
from django.views.generic import CreateView

from .models import Article


class ArticleCreateView(CreateView):
    model = Article
    fields = ["title", "content"]
    template_name = "articles/article_form.html"
    success_url = reverse_lazy("article-list")

This view handles:

  • displaying the form
  • validating submitted data
  • saving the object
  • redisplaying form errors
  • redirecting after success

The form is available in the template as:

django

1
{{ form }}

Example template:

django

1
2
3
4
5
<form method="post">
    {% csrf_token %}
    {{ form.as_p }}
    <button type="submit">Create article</button>
</form>

Setting Values Before Saving

Override form_valid():

python

1
2
3
4
5
6
7
8
9
class ArticleCreateView(CreateView):
    model = Article
    fields = ["title", "content"]
    template_name = "articles/article_form.html"
    success_url = reverse_lazy("article-list")

    def form_valid(self, form):
        form.instance.author = self.request.user
        return super().form_valid(form)

This sets the current user as the article’s author before the object is saved.

UpdateView

UpdateView edits an existing object.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.urls import reverse_lazy
from django.views.generic import UpdateView

from .models import Article


class ArticleUpdateView(UpdateView):
    model = Article
    fields = ["title", "content"]
    template_name = "articles/article_form.html"
    success_url = reverse_lazy("article-list")

URL pattern:

python

1
2
3
4
5
path(
    "articles/<int:pk>/edit/",
    ArticleUpdateView.as_view(),
    name="article-update",
)

UpdateView retrieves the object, fills the form with its current data, validates changes, and saves the updated object.

DeleteView

DeleteView displays a confirmation page and deletes an object after a POST request.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.urls import reverse_lazy
from django.views.generic import DeleteView

from .models import Article


class ArticleDeleteView(DeleteView):
    model = Article
    template_name = "articles/article_confirm_delete.html"
    success_url = reverse_lazy("article-list")

URL pattern:

python

1
2
3
4
5
path(
    "articles/<int:pk>/delete/",
    ArticleDeleteView.as_view(),
    name="article-delete",
)

Example confirmation template:

django

1
2
3
4
5
6
7
8
<h1>Delete article</h1>

<p>Are you sure you want to delete "{{ article.title }}"?</p>

<form method="post">
    {% csrf_token %}
    <button type="submit">Delete</button>
</form>

Deletion should normally be performed through POST, not GET.

FormView

FormView handles forms that are not directly tied to creating or updating a model.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
from django.urls import reverse_lazy
from django.views.generic import FormView

from .forms import ContactForm


class ContactView(FormView):
    template_name = "contact/contact_form.html"
    form_class = ContactForm
    success_url = reverse_lazy("contact-success")

    def form_valid(self, form):
        form.send_message()
        return super().form_valid(form)

Use FormView for forms such as:

  • contact forms
  • search forms
  • feedback forms
  • subscription forms
  • custom workflow forms

Common Class Attributes

Generic views are often configured through class attributes.

Attribute Purpose
model Model used by the view
template_name Template to render
context_object_name Name used in template context
queryset Base queryset
fields Model fields included in a generated form
form_class Custom form class
success_url Redirect destination after success
slug_field Model field used for slug lookup
slug_url_kwarg URL keyword containing the slug
paginate_by Number of objects per page

Example:

python

1
2
3
4
5
class ArticleListView(ListView):
    model = Article
    template_name = "articles/article_list.html"
    context_object_name = "articles"
    paginate_by = 10

Common Methods to Override

Class-based views can be customized by overriding methods.

Common methods include:

Method Purpose
get_queryset() Return the objects used by the view
get_context_data() Add values to template context
get_object() Retrieve the main object
get_form() Return the form instance
get_form_kwargs() Add arguments passed to the form
form_valid() Handle a valid form
form_invalid() Handle an invalid form
get_success_url() Determine the success redirect
dispatch() Handle the request before method routing

Overriding get_context_data()

Use get_context_data() to add extra template data.

python

1
2
3
4
5
6
7
8
9
class ArticleDetailView(DetailView):
    model = Article

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context["related_articles"] = Article.objects.exclude(
            pk=self.object.pk,
        )[:5]
        return context

The template can use:

django

1
2
3
{% for article in related_articles %}
    {{ article.title }}
{% endfor %}

Overriding get_queryset()

Use get_queryset() to control which objects are available.

python

1
2
3
4
5
6
7
8
class ArticleListView(ListView):
    model = Article
    context_object_name = "articles"

    def get_queryset(self):
        return Article.objects.filter(
            is_published=True,
        )

For user-specific data:

python

1
2
3
4
def get_queryset(self):
    return Article.objects.filter(
        author=self.request.user,
    )

Overriding get_success_url()

Use get_success_url() when the redirect depends on the saved object.

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.urls import reverse


class ArticleCreateView(CreateView):
    model = Article
    fields = ["title", "content"]

    def get_success_url(self):
        return reverse(
            "article-detail",
            kwargs={"pk": self.object.pk},
        )

After creating the article, the user is redirected to that article’s detail page.

reverse() and reverse_lazy()

Class attributes are evaluated when the module is imported.

For this reason, reverse_lazy() is commonly used for attributes such as success_url:

python

1
2
3
4
from django.urls import reverse_lazy


success_url = reverse_lazy("article-list")

Use reverse() inside methods:

python

1
2
3
4
5
6
7
8
from django.urls import reverse


def get_success_url(self):
    return reverse(
        "article-detail",
        kwargs={"pk": self.object.pk},
    )

A simple rule is:

text

1
2
Class attribute → reverse_lazy()
Method body     → reverse()

Mixins

A mixin is a class that adds reusable behavior to another class.

Django provides mixins for common requirements such as authentication and permissions.

LoginRequiredMixin

Require the user to be logged in:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import CreateView

from .models import Article


class ArticleCreateView(
    LoginRequiredMixin,
    CreateView,
):
    model = Article
    fields = ["title", "content"]

Mixins normally appear before the main generic view:

python

1
2
3
4
5
class ArticleCreateView(
    LoginRequiredMixin,
    CreateView,
):
    ...

UserPassesTestMixin

Apply a custom permission test:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
from django.contrib.auth.mixins import UserPassesTestMixin
from django.views.generic import UpdateView

from .models import Article


class ArticleUpdateView(
    UserPassesTestMixin,
    UpdateView,
):
    model = Article
    fields = ["title", "content"]

    def test_func(self):
        article = self.get_object()
        return article.author == self.request.user

This allows only the article’s author to edit it.

PermissionRequiredMixin

Require a Django permission:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
from django.contrib.auth.mixins import PermissionRequiredMixin
from django.views.generic import DeleteView


class ArticleDeleteView(
    PermissionRequiredMixin,
    DeleteView,
):
    model = Article
    permission_required = "articles.delete_article"

Method Resolution Order

Class-based views often inherit from several classes.

Python uses the method resolution order, or MRO, to decide which implementation runs first.

This matters when using mixins:

python

1
2
3
4
5
class ArticleCreateView(
    LoginRequiredMixin,
    CreateView,
):
    ...

The order of parent classes can affect behavior.

As a general rule:

  • place mixins first
  • place the main Django view class last
  • call super() when overriding cooperative methods

Example:

python

1
2
3
4
def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context["page_title"] = "Articles"
    return context

Failing to call super() may remove context or behavior provided by parent classes.

A Complete CRUD Example

Consider this model:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
from django.db import models


class Article(models.Model):
    title = models.CharField(max_length=200)
    content = models.TextField()
    is_published = models.BooleanField(default=False)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.title

The views can be written as:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
from django.urls import reverse_lazy
from django.views.generic import (
    CreateView,
    DeleteView,
    DetailView,
    ListView,
    UpdateView,
)

from .models import Article


class ArticleListView(ListView):
    model = Article
    template_name = "articles/article_list.html"
    context_object_name = "articles"
    ordering = ["-created_at"]


class ArticleDetailView(DetailView):
    model = Article
    template_name = "articles/article_detail.html"
    context_object_name = "article"


class ArticleCreateView(CreateView):
    model = Article
    fields = ["title", "content", "is_published"]
    template_name = "articles/article_form.html"
    success_url = reverse_lazy("article-list")


class ArticleUpdateView(UpdateView):
    model = Article
    fields = ["title", "content", "is_published"]
    template_name = "articles/article_form.html"
    success_url = reverse_lazy("article-list")


class ArticleDeleteView(DeleteView):
    model = Article
    template_name = "articles/article_confirm_delete.html"
    success_url = reverse_lazy("article-list")

The URL patterns are:

python

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
from django.urls import path

from .views import (
    ArticleCreateView,
    ArticleDeleteView,
    ArticleDetailView,
    ArticleListView,
    ArticleUpdateView,
)


urlpatterns = [
    path(
        "articles/",
        ArticleListView.as_view(),
        name="article-list",
    ),
    path(
        "articles/new/",
        ArticleCreateView.as_view(),
        name="article-create",
    ),
    path(
        "articles/<int:pk>/",
        ArticleDetailView.as_view(),
        name="article-detail",
    ),
    path(
        "articles/<int:pk>/edit/",
        ArticleUpdateView.as_view(),
        name="article-update",
    ),
    path(
        "articles/<int:pk>/delete/",
        ArticleDeleteView.as_view(),
        name="article-delete",
    ),
]

Together, these views provide basic create, read, update, and delete behavior.

Common Beginner Mistakes

Forgetting as_view()

Incorrect:

python

1
path("articles/", ArticleListView)

Correct:

python

1
path("articles/", ArticleListView.as_view())

Using the Wrong URL Parameter Name

Generic detail views expect pk by default:

python

1
2
3
4
path(
    "articles/<int:pk>/",
    ArticleDetailView.as_view(),
)

Using another name requires configuration:

python

1
2
3
class ArticleDetailView(DetailView):
    model = Article
    pk_url_kwarg = "article_id"

Forgetting to Call super()

Incorrect:

python

1
2
def get_context_data(self, **kwargs):
    return {"page_title": "Articles"}

This removes context created by the parent view.

Correct:

python

1
2
3
4
def get_context_data(self, **kwargs):
    context = super().get_context_data(**kwargs)
    context["page_title"] = "Articles"
    return context

Overriding Too Much

A generic view may already provide the needed behavior.

Before overriding a method, check whether a class attribute is enough.

Prefer:

python

1
2
3
class ArticleListView(ListView):
    model = Article
    context_object_name = "articles"

over rewriting the entire get() method without a clear reason.

Using Class-Based Views for Every View

Class-based views are not mandatory.

A small or unusual request flow may be clearer as a function-based view.

Use the style that makes the behavior easiest to understand.

Hiding Too Much Logic in Mixins

Mixins can reduce repetition, but too many mixins can make it difficult to determine where behavior comes from.

Keep inheritance structures understandable.

When to Use Class-Based Views

Class-based views are a good choice when:

  • the view follows a standard pattern
  • built-in generic views match the task
  • several views share behavior
  • authentication or permissions can be added with mixins
  • HTTP methods benefit from separate handlers
  • configuration through class attributes keeps the view simple

Function-based views may be clearer when:

  • the view has a short custom workflow
  • the logic does not match a generic view
  • several unrelated actions happen in one request
  • inheritance would make the flow harder to understand

Class-based views can feel difficult because their behavior is distributed across parent classes.

A practical learning order is:

  1. Learn the base View class.
  2. Write separate get() and post() methods.
  3. Learn TemplateView.
  4. Learn ListView and DetailView.
  5. Learn CreateView, UpdateView, and DeleteView.
  6. Practice overriding get_queryset().
  7. Practice overriding get_context_data().
  8. Add authentication and permission mixins.
  9. Inspect parent classes only when customization is required.

Do not try to memorize every method.

Start with the generic view that matches the task, configure its main attributes, and override only the behavior that needs to change.

Mini Reference

text

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
View
    Basic class-based request handling

TemplateView
    Render a template

ListView
    Display multiple objects

DetailView
    Display one object

CreateView
    Create a model object

UpdateView
    Edit a model object

DeleteView
    Delete a model object

FormView
    Display and process a form

Common configuration:

text

1
2
3
4
5
6
7
8
model
template_name
context_object_name
queryset
fields
form_class
success_url
paginate_by

Common methods:

text

1
2
3
4
5
6
7
8
9
get()
post()
get_queryset()
get_context_data()
get_object()
form_valid()
form_invalid()
get_success_url()
dispatch()

URL registration:

python

1
2
3
4
5
path(
    "articles/",
    ArticleListView.as_view(),
    name="article-list",
)

Django class-based views organize view behavior into Python classes.

The base View class separates request methods such as GET and POST, while generic views provide reusable implementations for common tasks such as listing, displaying, creating, updating, and deleting objects.

The main ideas to remember are:

  • class-based views are classes that handle requests
  • as_view() converts the class into a callable view
  • HTTP methods are handled by methods such as get() and post()
  • generic views provide common application patterns
  • class attributes configure standard behavior
  • methods can be overridden when customization is needed
  • mixins add reusable authentication and permission behavior
  • super() preserves behavior from parent classes

Class-based views are most useful when they simplify common patterns. They should reduce repetition and clarify structure, not make a straightforward view harder to understand.

Join the Newsletter

Practical insights on Django, backend systems, deployment, architecture, and real-world development — delivered without noise.

Get updates when new guides, learning paths, cheat sheets, and field notes are published.

No spam. Unsubscribe anytime.



There is no third-party involved so don't worry - we won't share your details with anyone.