正如标题所问,为什么Django成员决定使用querydict实现request.post对象(当然,这反过来又使整个对象不可变?)
我知道你可以通过复制一份邮寄数据来破坏它
1
| post = request.POST.copy() |
但为什么要这样做?当然,仅仅允许事物是可变的会更简单些吗?还是因为其他原因使用,可能导致问题?
- 你为什么要它是可变的?您可以从中获取数据,并在视图中使用/修改它。通过向其中添加数据,您可能会产生这样的印象:request.POST提交的数据比实际提交的数据多。
- 不是我想要它是可变的。我只想让冰淇淋变冷。不过,就冰淇淋而言,如果不冷,它就会融化,然后你会因为弄得一团糟而被责骂。但是使用request.post对象…我的意思是,如果我要搞砸我的代码,我会搞砸的。我不知道开发人员向Post对象添加数据并导致问题的普遍性,所以以"修复"为目标似乎很奇怪。
- 问得好,从来没想过。
- 这对我来说是偶尔出现的,因为我的客户机有时提交JSON数据(可变的),有时提交URL格式编码(不可变的)消息。
- 对于非英语使用者来说,"mutify"不是一个词——正确的短语是"你可以改变它"或"你可以修改它"。也没有必要对开发人员进行性别划分——你可以使用"Django团队"或"核心开发人员",而不是"家伙"。
这有点神秘,不是吗?一些表面上看似合理的理论在调查中被证明是错误的:
所以POST对象不必实现突变方法?否:POST对象属于django.http.QueryDict类,实现了包括__setitem__、__delitem__、pop、clear等一整套突变方法。它通过在调用其中一个突变方法时检查标志来实现不变性。当您调用copy方法时,会得到另一个QueryDict实例,该实例的可变标志已打开。
为了提高绩效?否:关闭可变标志时,QueryDict类不会获得性能优势。
这样,POST对象就可以用作字典键了?否:QueryDict对象不可哈希。
因此,可以像这里所说的那样,延迟地构建POST数据(而不承诺读取整个响应)?我在代码中看不到这方面的证据:据我所知,整个响应始终是直接读取的,或者通过MultiPartParser读取multipart响应。
为了防止编程错误?我见过这个声明,但是我从来没有看到过一个很好的解释,这些错误是什么,以及不可变如何保护您免受它们的影响。
在任何情况下,POST并不总是不变的:当响应为multipart时,POST是可变的。这似乎使你所想到的大多数理论都有点模棱两可。(除非这种行为是一种监督。)
综上所述,Django没有明确的理由认为POST反对非multipart请求不可变。
- 我注意到在Django有很多这样粗糙的边缘。不过,在某种程度上肯定对某人有意义。
- 我在另一个堆栈回答中发现了这一点:"它必须是不可变的,以便可以懒惰地构建它。拷贝强制获取所有的post数据。在收到副本之前,不能全部提取。此外,对于一个多线程的WSGi服务器来说,如果它是不可变的,那么它将很有帮助。"
- @肖克斯:看我的观点。
- 啊,对不起,我错过了。我只看了问题和你文章的前2点。只是想表现得好一点,然后跟进我在别处找到的信息。也许它用于延迟加载,但现在不行了,而querydict是只需要替换的代码?小精灵。
- @当你打算评论这些答案时,你不应该懒散地阅读它们。;-)
- @基督城我看到你在那里做了什么
- 更好的是,当我发送请求起诉Django测试客户机时,querydict是可变的。
如果该请求是Django form提交的结果,那么以immutable的身份发布是合理的,以确保表单提交和表单验证之间的数据完整性。但是,如果请求不是通过Django form提交发送的,那么post是mutable,因为没有表单验证。
你总是可以这样做:(根据狂人@leo的评论)
1 2 3 4 5 6
| # .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ...... |
- @乔希:我想评论员想让帖子变点,这个答案中的代码片段有帮助。
- 可以添加新的键、值,但不能更改现有数据。
- 很好。我相信使用这段代码的人都知道他或她在做什么。
更新:
加雷思·里斯是对的,第1点和第3点在本案中无效。尽管我认为第2点和第4点仍然有效,所以我将把这些留在这里。
(我注意到金字塔(塔架)和Django的request.POST物体是MultiDict的某种形式。因此,也许这比使request.POST不变更为常见。)
我不能代表姜戈人说话,尽管在我看来,这可能是因为以下一些原因:
性能。不可变对象比可变对象"更快",因为它们允许大量优化。一个对象是不可变的,这意味着我们可以在创建时为它分配空间,而空间需求并没有改变。因为它还具有复制效率和比较效率。罢工>编辑:正如加雷思·里斯所指出的,这不是QueryDict的情况。
在request.POST的情况下,服务器端的活动似乎不需要更改请求的数据。因此,不变的对象更适合,更不用说它们具有实质性的性能优势。
不可变对象可以用作dict键,我认为这在django的某个地方非常有用。罢工>编辑:我的错误是,不可变并不直接意味着可哈希;但是,可哈希对象通常也是不可变的。
当您传递request.POST时(尤其是传递给第三方插件和输出),您可以期望来自用户的这个请求对象保持不变。
在某种程度上,这些原因也是"不变与可变"的一般答案。问题。我敢肯定,在Django案例中,有比上面更多的设计考虑。
- 最后一个案例真的很重要。这是关于安全的。这就是Django提供sessions的原因,sessions是获取和修改州之间数据的短实时方式。
- 在这种情况下,您的观点(1)不能是答案,因为POST是QueryDict对象,这些对象不可变,因此没有性能优势。你的观点(3)不能作为答案,因为QueryDict对象不可散列,因此不能用作字典键。
- @Garethres感谢你指出这些。我的确错了。我更新了我的答案以更正这些问题。在我回答之前,我应该多关注一下QueryDict。
- @CPPLearner安全点似乎没有什么意义,例如requests.POST._mutable = True; requests.POST['foo'] = 'bar'; request.POST._mutable = False
我喜欢它在默认情况下是不变的。正如所指出的,如果需要的话,您可以使它变为可变的,但您必须明确地说明这一点。这就像"我知道我可以让窗体调试成为一场噩梦,但我知道我现在在做什么"。
我在堆栈回答的评论中找到了这个https://stackoverflow.com/a/2339963
And it must be immutable so that it can be built lazily. The copy forces getting all the POST data. Until the copy, it may not all be fetched. Further, for a multi-threaded WSGI server to work reasonably well, it's helpful if this is immutable
号
请注意:django 1.11以来,multipart请求是不可变的。https://github.com/django/django/blob/stable/1.11.x/django/http/multipartparser.py_l292
它们在以前的版本中是可变的。