SyntaxStudy
Sign Up
Django Mixins, Context Data, and View Customisation
Django Beginner 1 min read

Mixins, Context Data, and View Customisation

get_context_data() is the primary hook for adding extra data to a template's context in CBVs. You call super().get_context_data() to get the default context dictionary, add your own keys, and return the updated dictionary. This pattern works across all generic views and keeps your templates clean by providing all necessary data from the view rather than embedding logic in templates. Custom mixins are reusable classes that you combine with generic views to add cross-cutting behaviour. Common examples include an OwnerRequiredMixin that checks object ownership, a SuccessMessageMixin that flashes a success message after a form save, or a CacheMixin that adds cache headers to responses. Mixins must be listed before the generic view class in the inheritance chain so Python's Method Resolution Order (MRO) processes them first. Django's as_view() method converts a CBV class into a view callable that can be used in URL patterns. You can pass keyword arguments to as_view() to override class-level attributes on a per-URL basis, which is useful for reusing the same CBV class with different templates or querysets in different URL routes.
Example
# blog/views.py — mixins and get_context_data customisation
from django.views.generic import ListView, DetailView
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib import messages
from .models import Post, Tag


class SuccessMessageMixin:
    success_message = ''

    def form_valid(self, form):
        response = super().form_valid(form)
        if self.success_message:
            messages.success(self.request, self.success_message)
        return response


class OwnerRequiredMixin:
    """Restrict edit/delete to the object owner."""
    def dispatch(self, request, *args, **kwargs):
        obj = self.get_object()
        if obj.author != request.user:
            from django.core.exceptions import PermissionDenied
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)


class PostListView(ListView):
    model               = Post
    template_name       = 'blog/post_list.html'
    context_object_name = 'posts'
    paginate_by         = 10

    def get_queryset(self):
        qs = Post.published.select_related('author')
        tag_slug = self.kwargs.get('tag_slug')
        if tag_slug:
            self.tag = Tag.objects.get(slug=tag_slug)
            qs = qs.filter(tags=self.tag)
        return qs.order_by('-published_at')

    def get_context_data(self, **kwargs):
        context = super().get_context_data(**kwargs)
        context['all_tags']    = Tag.objects.all()
        context['active_tag']  = getattr(self, 'tag', None)
        context['total_posts'] = Post.published.count()
        return context


# blog/urls.py — as_view() usage
from django.urls import path
from . import views

urlpatterns = [
    path('', views.PostListView.as_view(), name='post-list'),
    path('tag/<slug:tag_slug>/', views.PostListView.as_view(), name='posts-by-tag'),
]