Search code examples
pythondjangopostpython-requestsdjango-csrf

Does Django's csrf_exempt decorator remove all POST data?


I have a Django view which returns a list of objects, or allows you to create one if you POST...

@csrf_exempt
def quantities(request):
    if request.method == "POST":
        kwargs = {**request.POST}
        print(request.POST)
        quantity = Quantity.objects.create(**kwargs)
        return JsonResponse({"quantity": f"/quantities/{quantity.id}/"})
    return JsonResponse([], safe=False)

If it gets a GET request it returns a list of quantities (code not shown), which works fine, and if it gets a POST request it uses POST data to create a new quantity. (I'm aware DRF does all this for you, but for my first API I wanted to try doing it manually - you just understand it better that way.)

Anyway in my test, I use requests to check this works...

response = requests.post(
 self.live_server_url + f"/quantities/", data={
  "name": "Height", "units": "m", "description": "Human Height"
 }
)

This doesn't work - it doesn't pass any data. That print statement in the view above just prints <QueryDict: {}>. For some reason the POST data that I put in the request has gone from the request by the time it passes through all the middleware and gets to the view.

The only thing I can think of is that the @csrf_exempt decorator is removing POST data, though I can't imagine why. I've looked at its source code and it doesn't seem to be doing that, but I can't check because removing the decorator means the view just returns a 403 response.

Where is my POST data going?


Solution

  • So it turns out that for some reason the fact that my request had a header "Content-Type": "application/json" was making Django not create a POST dictionary from the request body. I have no idea why but removing that header fixed the issue.