Where/how 替换 Django CBV 中的默认上传处理程序?

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

我正在尝试为基于 class 的视图指定处理文件上传的特定方法。根据 docs 这可以通过以下方式实现:

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

如果我在 FormViewpost 方法中这样指定:

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

我得到:

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

类似的变体产生相同的结果:

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)

然而,当我在 get 方法中这样做时,这是无效的:

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

如果我上传一个小文件,它仍然使用默认的 django.core.files.uploadhandler.MemoryFileUploadHandler

我做错了什么?

编辑

此外,当我尝试反映 note 中的建议时,我得到了相同的结果 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)

因为您不能更改视图中的上传处理程序,因为它是在您的视图函数之前被调用的东西。

Get 不应收集 post 参数,因此它会相应地运行。

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"]

如果您想要不同的上传处理程序,您可以更改 FILE_UPLOAD_HANDLERS 设置

如果这还不够你可以写下你的custom upload handler

编辑:

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.

好的,终于让它工作了(使用@Alasdair 提供的建议)。在 post 上设置 method decorator(crsf_exempt) 是不够的,它需要在 dispatch 上设置。对于将来为此苦苦挣扎的任何人,它是这样的:

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)

如果您从模板中删除 {% csrf_token %}(这正是您想要的),它也会失败。