访问表单的正文

时间:2017-05-23 08:32:19

标签: django django-forms

我正在存储request.body数据,以便我可以在之后恢复原始表单。 您似乎只能阅读request.body一次。第二次出现RawPostDataException异常。

问题是我在表单中添加了forms.FileField。现在看来,即使第一次访问request.body也会因RawPostDataException异常而失败。

看起来当在表单中发送文件时,Django会执行某些操作并读取request.body对象,实际上将其锁定后再进行读取。甚至在Form对象初始化之前就会发生这种情况。

这是一个错误吗?如何以其他方式访问request.body内容?

我正在使用最新的Django(1.11.1)。

4 个答案:

答案 0 :(得分:1)

我强烈认为您应该朝着使用request.POST的方向前进。以下是如何序列化和反序列化的示例:

In [1]: from django.test import RequestFactory

In [2]: from django.http.request import QueryDict

In [3]: request = RequestFactory().post('/', {'foo': 'bar', 'bazz': 'spam'})

In [4]: request.POST
Out[4]: <QueryDict: {'foo': ['bar'], 'bazz': ['spam']}>

In [5]: request.POST.urlencode()
Out[5]: 'foo=bar&bazz=spam'

In [6]: QueryDict('foo=bar&bazz=spam')
Out[6]: <QueryDict: {'foo': ['bar'], 'bazz': ['spam']}>

如果您想使用字典并将(de)序列化保留到json.dumps / json.loads,还有另一种选择:

In [7]: qdict = QueryDict('', mutable=True)

In [8]: qdict.update({'foo': 'bar', 'bazz': 'spam'})

In [9]: qdict
Out[9]: <QueryDict: {'foo': ['bar'], 'bazz': ['spam']}>

答案 1 :(得分:0)

您的HTML表单中是否有enctype="multipart/form-data"属性?否则,在您的请求中发送文件时通常会导致问题。

答案 2 :(得分:0)

由于各种原因,Django只允许读取一次POST主体。由于正文使用类似文件的API公开,因此无法再轻松读取该文件。此外,如果您已经阅读过数据,则无法更改upload file handlers。无法仅读取一次POST数据将失败,并且由于两个原因调试很棘手。

  • Django仅在您第二次访问正文时报告错误,因此第一次访问正文时可能很难跟踪。
  • 无数不同的问题可能会导致这种情况。一种方法是在读取数据时打印完整的回溯(使用traceback.print_stack())(在django / http / request.py中:HttpRequest.read和HttpRequest.readline)。

那么,您是否在代码中的某处访问了request.method?你在使用Django测试客户端吗?我还有很多其他原因。

来自文档,

  

HttpRequest.body¶

     

原始HTTP请求正文作为字节字符串。这对于以不同于传统HTML表单的方式处理数据非常有用:二进制映像,XML有效负载等。对于处理传统表单数据,请使用HttpRequest.POST。

在搜索了这个背景之后,我偶然发现了ticket (HTTPRequest::raw_post_data broken for tests)

在机票中,有明确说明,

  

这是一个假定的不变量,你不会访问曾经读过一次的raw_post_data,但问题是有两条路径可以读取它,其中一条(非多部分)填充_raw_post_data备忘录(因此你可以随后多次访问raw_post_data),其中一个(多部分)没有,后者基于多部分数据可以“大”并且它会咀嚼内存。

但是,经过这么说之后,有一项工作根本不安全,事实上要说。通过禁用'django.middleware.csrf.CsrfViewMiddleware',可以实现它。

从process_request或process_view访问middleware内的request.POST将阻止在中间件之后运行的任何视图能够修改请求的上传处理程序,并且通常应该避免。 CsrfViewMiddleware类可以被视为异常,因为它提供了csrf_exempt()csrf_protect()装饰器,允许视图明确控制CSRF验证应在何时发生。

答案 3 :(得分:0)

如果目标是保存表单以便以后重新执行,则可以使用:

form.save(commit=False)

无需再保存request.Post