85
class ChromeLoginView(View): def get(self, request): return JsonResponse({'status': request.user.is_authenticated()}) @method_decorator(csrf_exempt) def post(self, request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) return JsonResponse({'status': True}) return JsonResponse({'status': False}) 

I am expecting that the post does stopped by csrf, but it return 403 error.

But if remove that decorator and do this in the URLConf

url(r'^chrome_login/', csrf_exempt(ChromeLoginView.as_view()), name='chrome_login'), 

it will work.

What happened here? didn't it supposed to work, because I guess that's what method_decorator do. I'm using python3.4 and django1.7.1

Any advice would be great.

4
  • 1
    You should look into the django_braces... Commented Dec 5, 2014 at 13:28
  • 1
    It's super awesome! Especially since you can simply add the CsrfExemptMixin to your view to make this work. It's almost like cheating... Commented Dec 5, 2014 at 14:37
  • In my use case I am not using a form, so how can I still include a csrf token in my application? Like I am creating APIs hence a UI doesn't come into picture. So how can I make sure that CSRF token is still passed? Commented Sep 30, 2017 at 10:41
  • These answers won't work for DRF. See stackoverflow.com/questions/30871033/… Commented Aug 28, 2020 at 17:29

5 Answers 5

152

As @knbk said, this is the dispatch() method that must be decorated.

Since Django 1.9, you can use the method_decorator directly on a class:

from django.utils.decorators import method_decorator @method_decorator(csrf_exempt, name='dispatch') class ChromeLoginView(View): def get(self, request): return JsonResponse({'status': request.user.is_authenticated()}) def post(self, request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) return JsonResponse({'status': True}) return JsonResponse({'status': False}) 

This avoids overriding the dispatch() method only to decorate it.

Sign up to request clarification or add additional context in comments.

Comments

103

You need to decorate the dispatch method for csrf_exempt to work. What it does is set an csrf_exempt attribute on the view function itself to True, and the middleware checks for this on the (outermost) view function. If only a few of the methods need to be decorated, you still need to use csrf_exempt on the dispatch method, but you can use csrf_protect on e.g. put(). If a GET, HEAD, OPTIONS or TRACE HTTP method is used it won't be checked whether you decorate it or not.

class ChromeLoginView(View): @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): return super(ChromeLoginView, self).dispatch(request, *args, **kwargs) def get(self, request): return JsonResponse({'status': request.user.is_authenticated()}) def post(self, request): username = request.POST['username'] password = request.POST['password'] user = authenticate(username=username, password=password) if user is not None: if user.is_active: login(request, user) return JsonResponse({'status': True}) return JsonResponse({'status': False}) 

Comments

6

If you are looking for Mixins to match your needs, then you can create a CSRFExemptMixin and extend that in your view no need of writing above statements in every view:

class CSRFExemptMixin(object): @method_decorator(csrf_exempt) def dispatch(self, *args, **kwargs): return super(CSRFExemptMixin, self).dispatch(*args, **kwargs) 

After that Extend this in your view like this.

class ChromeLoginView(CSRFExemptMixin, View): 

You can extend that in any view according to your requirement, That's reusability! :-)

Cheers!

Comments

2

Django braces provides a CsrfExemptMixin for this.

from braces.views import CsrfExemptMixin class ChromeLoginView(CsrfExemptMixin, View): ... 

Comments

2

You can achieve the desired results directly in the urls.py file related to the specific views.py app.

from django.views.decorators.csrf import csrf_exempt from django.urls import path urlpatterns = [path('validate-email', csrf_exempt(EmailValidationView.as_view())] 

Then just use your class in your views.py normally.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.