Django @csrf_exempt decorator not working

5.8k Views Asked by At

I'm using DJango 1.8 on a linode server, and have the following view:

import json

from django.http import HttpResponse
from django.shortcuts import render
from django.views.decorators.csrf import csrf_exempt

def home_view(request):
        r = { 'response': 'OK', 'data': None }
        return HttpResponse(json.dumps(r), content_type = "application/json")

@csrf_exempt
def ping(request):
        r = { 'response': 'OK', 'data': 'ping' }
        return HttpResponse(json.dumps(r), content_type = "application/json")

My urls look like this:

urlpatterns = [
    url(r'^django/admin/', include(admin.site.urls)),
    url(r'^django/$', home_view),
    url(r'^django/ping/$', ping),
    url(r'^django/echo/$', echo),
]

If I go to my linode site at http://mylinodesite/django/ping/

I get:

{"data": "ping", "response": "OK"}

Great. If I use jquery and do a

$.get("http://mylinodesite/django/ping/")

I get

No 'Access-Control-Allow-Origin' header is present on the requested resource.

From what I understand the @csrf_exempt is supposed to get rid of the CSRF header stuff. What gives?

2

There are 2 best solutions below

0
On BEST ANSWER

Daniel, turns out you're partially right. It's CORS but it cannot be fixed on the jQuery side. Here's my Django view code that does what I want. Note that it adds the Access-Control-Allow-Origin header to allow requests from all (*) for GET only.

This is also just a demonstration of how to do this all in one file. One could create middleware to do this for all requests if needed, but this works and is a good example of how to do it all in one place so you can see what is going on, and here is the full gist of the entire view file:

def ping(request):
        r = { 'response': 'OK', 'data': 'ping' }
        response = HttpResponse("['ok']", content_type="application/json")
        response['Access-Control-Allow-Origin'] = '*'
        response['Access-Control-Allow-Methods'] = 'GET'

        return response
1
On

This has nothing whatsoever to do with CSRF, which is for POST actions only and is enforced by Django.

You are doing a cross-domain GET action. Browsers forbid this by default because of what is called the same-origin policy: a JS script can only make requests to the same domain it is loaded from. So, you are being prevented by the browser itself.

To enable requests to named domains, you can use something called CORS, which uses a header in the request. See the jQuery Ajax documentation.