from django.core.exceptions import PermissionDenied
class UserOwnershipMixin:
"""Ensure the object belongs to the current user."""
def get_object(self, queryset=None):
obj = super().get_object(queryset)
if obj.owner != self.request.user:
raise PermissionDenied("You don't own this object")
return obj
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views.generic import UpdateView
from .mixins import UserOwnershipMixin
from .models import Post
class PostUpdateView(LoginRequiredMixin, UserOwnershipMixin, UpdateView):
model = Post
fields = ['title', 'content', 'published']
template_name = 'blog/post_form.html'
def get_queryset(self):
# Only show posts owned by current user
return super().get_queryset().filter(owner=self.request.user)
Mixins let me compose view behavior without duplication. LoginRequiredMixin is essential for protecting views. I create custom mixins like UserOwnershipMixin to encapsulate common patterns. Mixin order matters due to Python's MRO—I put Django's mixins first, then custom mixins, then the base view class. By overriding get_queryset or get_object, I can add filtering or prefetching logic. This keeps views DRY and makes it easy to apply consistent rules across multiple views. Testing mixins in isolation also improves coverage.