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

谁都会走 提交于 2021-02-10 05:53:07

问题


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)

回答1:


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).




回答2:


Because you cannot change upload handler in view as it is something that gets invoked prior to your view function.

Get shouldn't collect post parameters so it behaves accordingly.

Upload Handlers

When a user uploads a file, Django passes off the file data to an upload handler – a small class that handles file data as it gets uploaded. Upload handlers are initially defined in the FILE_UPLOAD_HANDLERS setting, which defaults to:

 ["django.core.files.uploadhandler.MemoryFileUploadHandler",
 "django.core.files.uploadhandler.TemporaryFileUploadHandler"]

If you want different upload handler you can change FILE_UPLOAD_HANDLERS settings

If this is not enough you can write your custom upload handler

Edit:

Also, request.POST is accessed byCsrfViewMiddleware which is enabled by default. This means you will need to use csrf_exempt() on your view to allow you to change the upload handlers.



来源:https://stackoverflow.com/questions/47438330/where-how-to-replace-default-upload-handler-in-django-cbv

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!