Search code examples
pythondjangodjango-formsdjango-file-upload

Where/how to replace default upload handler in Django CBV?


I am trying to specify a specific method of handling file uploads for a class based view. Per the docs this can be achieved by something like:

from django.core.files.uploadhandler import TemporaryFileUploadHandler
request.upload_handlers = [TemporaryFileUploadHandler(request=request)]

If i specify this in post method of a FormView like so:

def post(self, request, *args, **kwargs):
    request.upload_handlers = [TemporaryFileUploadHandler(request=request)]
    return super().post(self,  request, *args, **kwargs)

I get:

AttributeError: You cannot set the upload handlers after the upload has been processed.

Variants like yield the same result:

def post(self, request, *args, **kwargs):
    self.request.upload_handlers = [TemporaryFileUploadHandler(request=self.request)]
    form = self.get_form()
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

However when i do this in the get method this is ineffective:

 def get(self, request, *args, **kwargs):
    request.upload_handlers = [TemporaryFileUploadHandler(request=self.request)]  
    return super().get(self,  request, *args, **kwargs)

If I upload a small file it still uses the default django.core.files.uploadhandler.MemoryFileUploadHandler.

What am I doing wrong?

EDIT

Also when i try to mirror what is suggested in the note, I get the same AttributeError:

from django.views.decorators.csrf import csrf_exempt, csrf_protect

@csrf_exempt
def post(self, request, *args, **kwargs):
    request.upload_handlers = [TemporaryFileUploadHandler(request=request)]
    return self._post(request, *args, **kwargs)

@csrf_protect
def _post(self, request, *args, **kwargs):
    form = self.get_form()
    if form.is_valid():
        return self.form_valid(form)
    else:
        return self.form_invalid(form)

Solution

  • Ok, finally got it to work (using the suggestions provided by @Alasdair). Setting a method decorator(crsf_exempt) on post is not engough it needs to be on dispatch. For anyone struggling with this in the future, it goes like this:

    from django.views.generic import FormView
    from django.utils.decorators import method_decorator
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    
    
    @method_decorator(csrf_exempt, 'dispatch')
    class UploadDataSetView(FormView):
    
        def post(self, request, *args, **kwargs):
            request.upload_handlers = [TemporaryFileUploadHandler(request=request)]  
            return self._post(request)
    
        @method_decorator(csrf_protect)
        def _post(self, request):
            form = self.get_form()
            if form.is_valid():
                return self.form_valid(form)
            else:
                return self.form_invalid(form)
    

    Also it will fail if you remove the {% csrf_token %} from your template (which is what you want).