vistas tutoriales facilito codigofacilito codigo clases basadas django django-views django-csrf

tutoriales - vistas basadas en clases django



¿Cómo modifico los manejadores de carga de archivos en una vista basada en clases con middleware CSRF? (1)

Con la ayuda de un colega, he encontrado una manera fea de usar el middleware CSRF para verificar el token manualmente dentro de View. Aquí está la receta:

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)

Creo que hay margen de mejora en Django: en mi opinión, el middleware de CSRF debería proporcionar un método check_token separado check_token en process_view .

En mi proyecto de Django, tendré que modificar la tupla de los manejadores de carga de archivos "sobre la marcha" según lo documentado , para poder modificar la secuencia de archivos a medida que se cargan. Necesito esto "sobre la marcha", porque tengo que proporcionarle al manejador algunos datos de la Vista (vea setup() método setup() en el código a continuación).

La documentación también menciona cómo cuidar de hacer esto si usa protección CSRF. Esto es especial porque el middleware de protección CSRF accede a los datos POST en la solicitud, lo que da como resultado que el proceso de carga de archivos se active en el momento anterior a que se llame a mi vista. Sin embargo, esto solo está documentado para Vistas antiguas, pero quiero lograr lo mismo con una Vista basada en clase.

Aquí hay un ejemplo de código mínimo de mi Vista:

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)

El error que obtengo al usar @csrf_protect en el método de post es:

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''

Entonces, ¿cómo puedo tener la combinación de las siguientes tres propiedades de mi Vista?

  • el uso de vistas basadas en clase
  • capacidad de modificar el controlador de carga de archivos "sobre la marcha"
  • adecuada protección CSRF en la vista

Versión de Django utilizada: 1.5.1, Python 2.7.3.