Good Code
The good version requires POST, requires a logged-in user, and leaves CSRF middleware active for the state-changing action.
Lesson 07
Protect state-changing requests with Django's CSRF flow instead of exempting views for convenience.
from django.contrib.auth.decorators import login_required
from django.shortcuts import get_object_or_404, redirect
from django.views.decorators.http import require_POST
from .models import Review
@require_POST
@login_required
def publish_review(request, pk):
review = get_object_or_404(Review, pk=pk, author=request.user)
review.publish()
return redirect("reviews:detail", pk=review.pk)from django.http import JsonResponse
from django.views.decorators.csrf import csrf_exempt
from .models import Review
@csrf_exempt
def publish_review(request, pk):
review = Review.objects.get(pk=pk)
review.publish()
return JsonResponse({"ok": True})The good version requires POST, requires a logged-in user, and leaves CSRF middleware active for the state-changing action.
The bad version disables CSRF and skips ownership checks. It makes a sensitive action easy to call from places the app did not intend.