django - 为什么request.POST对象是不可变的?

bha*_*ral 107 django post

正如标题所示,为什么Django家伙决定使用querydict实现request.POST对象(当然,这反过来会使整个事情变得不可变?)

我知道你可以通过制作帖子数据的副本来弥补

post = request.POST.copy()
Run Code Online (Sandbox Code Playgroud)

但为什么这样呢?当然,只要让事情变得可变就更简单了?或者它是否也被用于其他可能导致问题的其他原因?

Gar*_*ees 128

这有点神秘,不是吗?一些表面上看似合理的理论在调查中被证明是错误的:

  1. 那么POST对象不必实现变异方法?编号:该POST对象所属的django.http.QueryDict,它实现了全套的突变方法,包括__setitem__,__delitem__,popclear.它通过在调用其中一种变异方法时检查标志来实现不变性.当你调用copy方法时,你会得到另一个QueryDict打开了mutable标志的实例.

  2. 为了提高性能?否:QueryDict当关闭可变标志时,该类不会获得性能优势.

  3. 这样POST对象可以用作字典键吗?不:QueryDict对象不可清洗.

  4. 这样声明POST可以懒惰地构建数据(不承诺读取整个响应),如此处所声明的那样?我没有看到这方面的证据代码:据我所知,整个反应总是读,无论是直接或通过MultiPartParsermultipart反应.

  5. 为了防止编程错误?我已经看到了这个声称,但我从来没有看到过这些错误的好解释,以及不变性如何保护你免受它们的攻击.

在任何情况下,POST不是永远不变的:当响应multipart,则POST是可变的.这似乎把你可能想到的大多数理论都放在了一边.(除非这种行为是疏忽.)

总之,我认为 Django 没有明确的理由说明POST对象对于非multipart请求是不可变的.

  • @Seaux当你想对它们发表评论时,你不应该懒洋洋地阅读SO答案.;-) (11认同)
  • @ChrisWesseling我看到你在那里做了什么 (3认同)
  • 我在另一个堆栈答案中发现了这一点:"它必须是不可变的,以便它可以懒惰地构建.复制强制获取所有POST数据.直到复制,它可能不会全部被提取.此外,对于多线程WSGI服务器工作得相当好,如果这是不可变的,这是有帮助的" (2认同)
  • 更好的是,当我发送起诉 django 测试客户端的请求时,querydict 是可变的。 (2认同)

un3*_*33k 79

如果请求是Django form提交的结果,那么POST immutable确保表单提交和表单验证之间的数据完整性是合理的.但是,如果请求通过Django 提交发送,则POST是因为没有表单验证.formmutable

你总是可以这样做:(根据@ leo-the-manic的评论)

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
Run Code Online (Sandbox Code Playgroud)

  • @JoshK:我想评论者希望POST变得可变,这个答案中的代码片段有帮助. (3认同)

K Z*_*K Z 5

更新:

Gareth Rees说得对,第1点和第3点在这种情况下无效.虽然我认为第2点和第4点仍然有效,但我会留下这些论文.

(我注意到request.POST金字塔(Pylon)和Django 的对象都是某种形式的MultiDict.所以也许它比request.POST不可变的更常见.)


我不能代表Django的人,虽然在我看来它可能因为以下一些原因:

  1. 表现.不可变对象比可变对象"更快",因为它们允许进行大量优化.对象是不可变的意味着我们可以在创建时为它分配空间,并且空间要求不会改变.它还具有复制效率和比较效率等特点. 编辑:这不是QueryDictGareth Rees指出的情况.
  2. 在这种情况下request.POST,似乎服务器端的任何活动都不需要改变请求的数据.因此,不可变对象更适合,更不用说它们具有很大的性能优势.
  3. 不可变对象可以用作dict键,我认为在Django的某个地方可能非常有用. 编辑:我的错误,不可变不直接暗示可以清除 ; 然而,可清洗对象通常也是不可变的.
  4. 当您传递request.POST(特别是第三方插件和外出)时,您可以预期来自用户的此请求对象将保持不变.

在某种程度上,这些原因也是"不可变与可变"的通用答案.题.我确信在Django案例中有更多的设计考虑因素.

  • @CppLearner安全点似乎没有实际意义,例如`requests.POST._mutable = True; requests.POST ['foo'] ='bar'; request.POST._mutable = False` (7认同)
  • 你的观点(1)在这种情况下不能成为答案,因为`POST`是一个[`QueryDict`对象](https://github.com/django/django/blob/master/django/http/__init__. py#L371),这些对象不会因为不可变而获得性能上的好处.并且您的观点(3)不能成为答案,因为`QueryDict`对象不可清除,因此不能用作字典键. (2认同)