Skip to main content
Course/Module 4/Topic 5 of 5Advanced

Advanced View Patterns

Learn advanced view patterns including mixins, decorators, and custom view behaviors for complex applications.

70 minBy Priygop TeamLast updated: Feb 2026

View Mixins and Decorators

Django provides powerful mixins and decorators that allow you to add functionality to views without duplicating code. These patterns help create reusable, maintainable view logic.

Custom Mixins and Decorators

Example
# Custom mixins for views
from django.contrib.auth.mixins import LoginRequiredMixin
from django.contrib.auth.decorators import login_required
from django.core.exceptions import PermissionDenied
from django.shortcuts import redirect
from django.contrib import messages

class AuthorRequiredMixin:
    """Mixin to ensure only the author can access the view"""
    
    def dispatch(self, request, *args, **kwargs):
        obj = self.get_object()
        if obj.author != request.user:
            raise PermissionDenied("You don't have permission to access this resource.")
        return super().dispatch(request, *args, **kwargs)

class StaffRequiredMixin:
    """Mixin to ensure only staff members can access the view"""
    
    def dispatch(self, request, *args, **kwargs):
        if not request.user.is_staff:
            messages.error(request, "Access denied. Staff privileges required.")
            return redirect('home')
        return super().dispatch(request, *args, **kwargs)

class CacheControlMixin:
    """Mixin to add cache control headers"""
    
    def dispatch(self, request, *args, **kwargs):
        response = super().dispatch(request, *args, **kwargs)
        response['Cache-Control'] = 'public, max-age=300'  # 5 minutes
        return response

# Custom decorators
def author_required(view_func):
    """Decorator to ensure only the author can access the view"""
    def wrapper(request, *args, **kwargs):
        from .models import Post
        post = get_object_or_404(Post, pk=kwargs['pk'])
        if post.author != request.user:
            messages.error(request, "You don't have permission to edit this post.")
            return redirect('post_detail', pk=post.pk)
        return view_func(request, *args, **kwargs)
    return wrapper

def rate_limit(limit=100, period=3600):
    """Decorator to implement rate limiting"""
    def decorator(view_func):
        def wrapper(request, *args, **kwargs):
            from django.core.cache import cache
            from django.http import HttpResponseTooManyRequests
            
            # Create a unique key for this user/IP
            key = f"rate_limit:{request.user.id if request.user.is_authenticated else request.META.get('REMOTE_ADDR')}"
            
            # Check current count
            current_count = cache.get(key, 0)
            
            if current_count >= limit:
                return HttpResponseTooManyRequests("Rate limit exceeded. Please try again later.")
            
            # Increment count
            cache.set(key, current_count + 1, period)
            
            return view_func(request, *args, **kwargs)
        return wrapper
    return decorator

# Usage examples
class PostEditView(AuthorRequiredMixin, LoginRequiredMixin, UpdateView):
    model = Post
    form_class = PostForm
    template_name = 'blog/post_form.html'

@login_required
@author_required
@rate_limit(limit=50, period=3600)
def edit_post(request, pk):
    # This view is rate-limited and author-restricted
    pass

Practice Exercise: View Factory Pattern

Example
# View Factory Pattern for Dynamic Views
from django.views.generic import ListView, DetailView
from django.db import models

class ViewFactory:
    """Factory class to create views dynamically"""
    
    @staticmethod
    def create_list_view(model, template_name=None, context_object_name=None, **kwargs):
        """Create a ListView for any model"""
        
        if template_name is None:
            template_name = f'{model._meta.app_label}/{model._meta.model_name}_list.html'
        
        if context_object_name is None:
            context_object_name = f'{model._meta.model_name}_list'
        
        class DynamicListView(ListView):
            model = model
            template_name = template_name
            context_object_name = context_object_name
            
            def get_queryset(self):
                """Filter queryset based on request parameters"""
                queryset = super().get_queryset()
                
                # Apply filters from query parameters
                for key, value in self.request.GET.items():
                    if hasattr(model, key) and value:
                        if isinstance(getattr(model, key), models.CharField):
                            queryset = queryset.filter(**{f'{key}__icontains': value})
                        else:
                            queryset = queryset.filter(**{key: value})
                
                return queryset
            
            def get_context_data(self, **kwargs):
                """Add dynamic context data"""
                context = super().get_context_data(**kwargs)
                
                # Add filter form context
                context['filters'] = self.request.GET
                context['model_name'] = model._meta.verbose_name_plural
                
                return context
        
        # Apply additional kwargs
        for key, value in kwargs.items():
            setattr(DynamicListView, key, value)
        
        return DynamicListView
    
    @staticmethod
    def create_detail_view(model, template_name=None, context_object_name=None, **kwargs):
        """Create a DetailView for any model"""
        
        if template_name is None:
            template_name = f'{model._meta.app_label}/{model._meta.model_name}_detail.html'
        
        if context_object_name is None:
            context_object_name = model._meta.model_name
        
        class DynamicDetailView(DetailView):
            model = model
            template_name = template_name
            context_object_name = context_object_name
            
            def get_context_data(self, **kwargs):
                """Add dynamic context data"""
                context = super().get_context_data(**kwargs)
                
                # Add related objects if they exist
                obj = self.get_object()
                
                # Look for related fields
                for field in model._meta.get_fields():
                    if field.is_relation and not field.auto_created:
                        try:
                            if field.many_to_many:
                                related_objects = getattr(obj, field.name).all()
                            else:
                                related_objects = getattr(obj, field.name)
                            
                            context[f'{field.name}_list'] = related_objects
                        except:
                            pass
                
                return context
        
        # Apply additional kwargs
        for key, value in kwargs.items():
            setattr(DynamicDetailView, key, value)
        
        return DynamicDetailView

# Usage example
from .models import Post, Category, Tag

# Create views dynamically
PostListView = ViewFactory.create_list_view(
    Post, 
    paginate_by=10,
    ordering=['-created_date']
)

CategoryListView = ViewFactory.create_list_view(
    Category,
    template_name='blog/category_list.html'
)

TagDetailView = ViewFactory.create_detail_view(
    Tag,
    template_name='blog/tag_detail.html'
)

# Register in urls.py
# urlpatterns = [
#     path('posts/', PostListView.as_view(), name='post_list'),
#     path('categories/', CategoryListView.as_view(), name='category_list'),
#     path('tag/<slug:slug>/', TagDetailView.as_view(), name='tag_detail'),
# ]

Try It Yourself — Views & Templates

Try It Yourself — Views & TemplatesHTML
HTML Editor
✓ ValidTab = 2 spaces
HTML|32 lines|1680 chars|✓ Valid syntax
UTF-8

Quick Quiz — Views & Templates

Additional Resources

Recommended Reading

  • Django Views Documentation
  • Django Templates Documentation
  • Django CBV by Classy Class-Based Views

Online Resources

  • Django Template Language
  • Django Generic Views
  • Template Tags and Filters
Chat on WhatsApp
Priygop - Leading Professional Development Platform | Expert Courses & Interview Prep