如何使用CSRF中间件修改基于类的View中的文件上传处理程序? [英] How do I modify the file upload handlers in a class based View with CSRF middleware?

查看:205
本文介绍了如何使用CSRF中间件修改基于类的View中的文件上传处理程序?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在我的Django项目中,我将不得不修改文件上传处理程序的元组即时如文档,以便能够在上传文件流时修改文件流。我需要这个即时,因为我必须提供处理程序的一些数据从视图(见下面的代码中的 setup()方法)。



如果您使用CSRF保护,文档还提到如何处理此问题。这是特别的,因为CSRF保护中间件在请求中访问POST数据,导致文件上传过程将在我的View被调用之前被触发。但是,这仅仅是对于旧式视图而言,但是我想使用基于类的视图来完成相同的操作。



这是我的视图的最小代码示例: / p>

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

class MyView(TemplateResponseMixin,ContextMixin,查看)
template_name ='mytemplate.html'

def __init __(self,* args,** kwargs):
self.fileuploadhandler = MyUploadHandler()
super(MyView,self).__ init __(* args,** kwargs)

def get(self,request,* args,** kwargs):
return self.render_to_response(
self.get_context_data(form = MyForm()))

#@ csrf_protect#这个错误低于
def post(self,request,* args,** kwargs):
#设置FileUploadHandler
#SNIP - 在这里收集一些数据
self.fileuploadhandler.setup(mydata)

#通过加载ModelForm
form = MyForm(request.POST,request.FILES)
处理POST数据如果form.is_valid():
#SNIP处理窗体
else:
return self.render_to_response(self.get_context_data(form = form))

def get_context_data(self,** kwargs):
context = super(MyView ,self).get_context_data(** kwargs)
返回上下文

@csrf_exempt#我必须这样做
def dispatch(self,* args,** kwargs):
self.request.upload_handlers.insert(0,self.fileuploadhandler)
返回超级(MyView,self).dispatch(* args,** kwargs)
/ pre>

使用 post @csrf_protect 时出现的错误c $ c>方法是:

 追溯(最近的最后一次呼叫):
文件/ some / path /到/ ENVS / someenv / local / lib目录/ python2.7 /站点包/ Django的/核心/处理器/基。 py,第115行,get_response
response = callback(request,* callback_args,** callback_kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/ site-packages / django / views / generic / base.py,第68行,视图
return self.dispatch(request,* args,** kwargs)
文件/ some / path / to /Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py,第25行,在_wrapper
中返回bound_func(* args,** kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py,第25行,_wrapped_view
return view_func(request,* args,** kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py,第21行,bound_func
return func(self,* args2,** kwargs2)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators。 py,第25行,在_wrapper
中返回bound_func(* args,** kwargs)
文件/ some / pat h / to / Envs / someenv / local / lib / python2.7 / site-packages / django / contrib / auth / decorators.py,第25行,_wrapped_view
return view_func(request,* args,** kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py,第21行,bound_func
返回func(self,* args2,** kwargs2)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py ,第77行,wrapped_view
return view_func(* args,** kwargs)
文件/some/path/to/project/myapp/views.py,行01234,在调度
return super(MyView,self).dispatch(* args,** kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/views /generic/base.py,第86行,在调度中
return handler(request,* args,** kwargs)
文件/ some / path / to / Envs / someenv / local / lib / python2.7 / site-packages / django / utils / decorators.py,第87行,_wrapped_view
result = middleware.process_view(r equest,view_func,args,kwargs)
文件/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/middleware/csrf.py,第95行, process_view
request.COOKIES [settings.CSRF_COOKIE_NAME])
AttributeError:'MyView'对象没有属性'COOKIES'

那么我该如何组合我的View的以下三个属性?




  • 使用基于类的视图

  • 能够即时修改文件上传处理程序

  • 正确的CSRF保护视图



使用的Django版本:1.5.1,Python 2.7.3。

解决方案

在同事的帮助下,我发现使用CSRF中间件在View中手动检查令牌是一种丑陋的方式。这是食谱:

  from django.views.decorators.csrf import csrf_exempt,csrf_protect 
from django.middleware.csrf导入CsrfViewMiddleware

类MyView(TemplateResponseMixin,ContextMixin,View):
template_name ='mytemplate.html'

def __init __(self,* args,** kwargs )
self.fileuploadhandler = MyUploadHandler()
super(MyView,self).__ init __(* args,** kwargs)

def post(self,request,* args ,** kwargs):
#设置FileUploadHandler
#SNIP - 在这里收集一些数据
self.fileuploadhandler.setup(mydata)

#检查CSRF手动*后*初始化文件上传处理程序。
csrf_checker = CsrfViewMiddleware()
csrf_error = csrf_checker.process_view(请求,无,无,无)
如果csrf_error不为无:
返回csrf_error#csrf_error是常规的CSRF错误查看

#通过加载ModelForm处理POST数据
form = MyForm(request.POST,request.FILES)
如果form.is_valid():
# SNIP处理窗体
else:
return self.render_to_response(self.get_context_data(form = form))

@csrf_exempt#重要的是跳过CSRF检查。
def dispatch(self,* args,** kwargs):
self.request.upload_handlers.insert(0,self.fileuploadhandler)
返回超级(MyView,self).dispatch(* args,** kwargs)

我认为这里有一些改进Django的空间 - CSRF中间件应该提供在我看来,在 process_view 中包含一个单独的 check_token 方法。


In my Django project I will have to modify the tuple of file upload handlers "on the fly" as documented, to have the ability to modify the file stream as it is being uploaded. I need this "on the fly", because I have to provide the handler some data from the View (see setup() method in the code below).

The documentation also mentions how to take care of doing this if you use CSRF protection. This is special because the CSRF protection middleware accesses the POST data in the request resulting in the file upload process will be fired at the time before my View gets called. However, this is only documented for old-style Views, but I want to accomplish the same using a Class Based View.

Here's a minimal code example of my View:

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

class MyView(TemplateResponseMixin, ContextMixin, View):
    template_name = 'mytemplate.html'

    def __init__(self, *args, **kwargs):
        self.fileuploadhandler = MyUploadHandler()
        super(MyView, self).__init__(*args, **kwargs)

    def get(self, request, *args, **kwargs):
        return self.render_to_response(
            self.get_context_data(form=MyForm()))

    #@csrf_protect                               # this gives the error below
    def post(self, request, *args, **kwargs):
        # Set up the FileUploadHandler
        # SNIP - some data is being gathered here
        self.fileuploadhandler.setup(mydata)

        # Process the POST data by loading the ModelForm
        form = MyForm(request.POST, request.FILES)
        if form.is_valid():
            # SNIP processing Form
        else:
            return self.render_to_response(self.get_context_data(form=form))

    def get_context_data(self, **kwargs):
        context = super(MyView, self).get_context_data(**kwargs)
        return context

    @csrf_exempt                                 # I have to do this
    def dispatch(self, *args, **kwargs):
        self.request.upload_handlers.insert(0, self.fileuploadhandler)
        return super(MyView, self).dispatch(*args, **kwargs)

The error I get when using @csrf_protect on the post method is:

Traceback (most recent call last):
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/core/handlers/base.py", line 115, in get_response
    response = callback(request, *callback_args, **callback_kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 68, in view
    return self.dispatch(request, *args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper
    return bound_func(*args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 25, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 21, in bound_func
    return func(self, *args2, **kwargs2)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 25, in _wrapper
    return bound_func(*args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/contrib/auth/decorators.py", line 25, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 21, in bound_func
    return func(self, *args2, **kwargs2)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/views/decorators/csrf.py", line 77, in wrapped_view
    return view_func(*args, **kwargs)
  File "/some/path/to/project/myapp/views.py", line 01234, in dispatch
    return super(MyView, self).dispatch(*args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/views/generic/base.py", line 86, in dispatch
    return handler(request, *args, **kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/utils/decorators.py", line 87, in _wrapped_view
    result = middleware.process_view(request, view_func, args, kwargs)
  File "/some/path/to/Envs/someenv/local/lib/python2.7/site-packages/django/middleware/csrf.py", line 95, in process_view
    request.COOKIES[settings.CSRF_COOKIE_NAME])
AttributeError: 'MyView' object has no attribute 'COOKIES'

So, how can I have the combination of the following three properties of my View?

  • the use of Class Based Views
  • ability to modify the file upload handler "on the fly"
  • proper CSRF protection on the View

Django version used: 1.5.1, Python 2.7.3.

解决方案

With the help of a colleague I've found a bit of an ugly way of using the CSRF middleware to check the token manually within the View. Here's the recipe:

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

class MyView(TemplateResponseMixin, ContextMixin, View):
    template_name = 'mytemplate.html'

    def __init__(self, *args, **kwargs):
        self.fileuploadhandler = MyUploadHandler()
        super(MyView, self).__init__(*args, **kwargs)

    def post(self, request, *args, **kwargs):
        # Set up the FileUploadHandler
        # SNIP - some data is being gathered here
        self.fileuploadhandler.setup(mydata)

        # Check CSRF manually *after* initializing the file upload handlers.
        csrf_checker = CsrfViewMiddleware()
        csrf_error = csrf_checker.process_view(request, None, None, None)
        if csrf_error is not None:
            return csrf_error # csrf_error is the regular CSRF error View

        # Process the POST data by loading the ModelForm
        form = MyForm(request.POST, request.FILES)
        if form.is_valid():
            # SNIP processing Form
        else:
            return self.render_to_response(self.get_context_data(form=form))

    @csrf_exempt # Important to skip CSRF checking here.
    def dispatch(self, *args, **kwargs):
        self.request.upload_handlers.insert(0, self.fileuploadhandler)
        return super(MyView, self).dispatch(*args, **kwargs)

I think here's some room for improvement in Django - the CSRF middleware should provide a separate check_token method wrapped in process_view, in my opinion.

这篇关于如何使用CSRF中间件修改基于类的View中的文件上传处理程序?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆