Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

DjangoRestFramework upload file 'CSRF Verification Failed'

I am using DjangoRestFramework to make an API. Currently I have OAuth2 authentication working which means I can generate a valid access token to use the API.

How do I upload a user file? I need to upload a file and relate it to the user who uploaded it.

I am currently trying to do it this way

api/views.py:

class FileUploadView(APIView):
    parser_classes = (FileUploadParser,)

    def put(self, request, filename, format=None):
        file_obj = request.FILES['file']
        # do stuff
        return Response(status=204)

api/urls.py contains this line:

url(r'^files/', 'api.views.FileUploadView'),

but when I try to upload a file I get an error stating that:

'CSRF verification failed. Request aborted'
'Reason given for failure: CSRF cookie not set'

when I try this curl command:

curl -XPUT http://localhost:8000/files/ -H 'Authorization: Bearer some_access_token' -F [email protected]

Here are my REST_FRAMEWORK defaults:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': ('rest_framework.permissions.IsAdminUser',),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework.authentication.OAuth2Authentication',
    )
}
like image 716
arnm Avatar asked Feb 27 '14 18:02

arnm


2 Answers

1) In my original code I was expecting a filename parameter to come into my view but I was not parsing it out of the url in urls.py. It should have looked something like this:

url(r'^uploads/(?P<filename>[\w.]{0,256})/$', views.UploadsView.as_view()),

2) I was also not providing the APIView as a view. If you notice above I am specifically calling the .as_view() method.

With the above fixed and implementing POST instead of PUT my code works as expected. Here is my current APIView:

class UploadsView(APIView):

    parser_classes = (FileUploadParser,)
    permission_classes = (permissions.IsAuthenticated,)

    def post(self, request, format=None):
        file_obj = request.FILES['file']
        print("FILE OBJ: ", file_obj)
        return Response(status=201)
like image 91
arnm Avatar answered Oct 22 '22 16:10

arnm


Per the Django REST Framework Documentation, "If you're using SessionAuthentication you'll need to include valid CSRF tokens for any POST, PUT, PATCH or DELETE operations.

In order to make AJAX requests, you need to include CSRF token in the HTTP header, as described in the Django documentation."

Alternatively, you can attempt to make this view CSRF Exempt:

from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt

class FileUploadView(APIView):
    parser_classes = (FileUploadParser,)

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(FileUploadView, self).dispatch(request, *args, **kwargs)

    def put(self, request, filename, format=None):
        file_obj = request.FILES['file']
        # do stuff
        return Response(status=204)
like image 27
Michael B Avatar answered Oct 22 '22 17:10

Michael B