16

I have the following code, that was working fine in Django 1.2.5:

from django.views.decorators.csrf import csrf_exempt

class ApiView(object):
    def __call__(self, request, *args, **kwargs):
        method = request.method.upper()
        return getattr(self, method)(request, *args, **kwargs)

@csrf_exempt
class MyView(ApiView):

    def POST(self):
       # (...)
       return HttpResponse(json.dumps(True), mimetype="text/javascript")

But when I upgraded to Django 1.4, I started to get a 403 forbidden, with a "CSRF verification failed" message.

Why is that @csrf_exempt decorator not working?

URL definition is:

from django.conf.urls.defaults import *
from django.views.decorators.csrf import csrf_exempt

import views

urlpatterns = patterns('',
   url(r'^myview/(?P<parameter_name>[A-Za-z0-9-_]+)/$',
       views.MyView(),
       name="myproject-myapp-myview",
       ),
)
Srikar Appalaraju
  • 71,928
  • 54
  • 216
  • 264
lfagundes
  • 2,978
  • 5
  • 24
  • 25

3 Answers3

22

According to the django docs:

To decorate every instance of a class-based view, you need to decorate the class definition itself. To do this you apply the decorator to the dispatch() method of the class.

So you'd need to do something like:

class MyView(ApiView):

    def POST(self):
       # (...)
       return HttpResponse(json.dumps(True), mimetype="text/javascript")

    @csrf_exempt
    def dispatch(self, *args, **kwargs):
        return super(MyView, self).dispatch(*args, **kwargs)
dgel
  • 16,352
  • 8
  • 58
  • 75
  • 2
    Since poster uses POST in capitals, i don't think he's using django class based views – Willian Apr 20 '12 at 20:07
  • @william- Good catch. This answer doesn't apply then. – dgel Apr 20 '12 at 20:10
  • yes, I'm not using the django class based view. I`m very sorry that I missed that MyView is a callable, as ApiView implements __call__ (I`m mantaining someone else's code). So, this class is a callable, and the @csrf_exempt on the class used to work in django 1.2, but does not in 1.4. – lfagundes Apr 23 '12 at 16:37
  • 2
    This wouldn't work anyway, even for class-based view. Per the docs, you have to wrap the csrf_exempt decorator in the method_decorator decorator: `@method_decorator(csrf_exempt)` – Chad Jul 19 '13 at 18:17
  • Finally. THANK GOD. That was bloody complicated. Thank you for providing an answer that actually works. – dan-klasson May 04 '17 at 13:02
12

Just use csrf_exempt in the urls.py. ie::

urls.py

..other imports...
from django.views.decorators.csrf import csrf_exempt   
from myapp.views import MyView

urlpatterns = patterns('',
   url(r'^myview/(?P<parameter_name>[A-Za-z0-9-_]+)/$',
       csrf_exempt(MyView.as_view()), # use csrf_exempt here
       name="myproject-myapp-myview",
       ),
)
Community
  • 1
  • 1
suhailvs
  • 20,182
  • 14
  • 100
  • 98
3

csrf_exempt has to decorate a function. In your urls you can decorate a that function, docs can be found here.

(r'^vote/', permission_required('polls.can_vote')(VoteView.as_view())),
Cesar Canassa
  • 18,659
  • 11
  • 66
  • 69
Willian
  • 2,385
  • 15
  • 17