正如标题所问,为什么 Django 家伙决定用 querydict 实现 request.POST 对象(当然,这反过来又使整个事情不可变?)
我知道你可以通过复制帖子数据来修改它
post = request.POST.copy()
但为什么要这样做?当然,无论如何允许事物是可变的会更简单吗?或者它是否也被用于其他可能导致问题的原因?
这有点神秘,不是吗?一些表面上看似合理的理论在调查中被证明是错误的:
这样POST
对象就不必实现变异方法了吗?否:该POST
对象属于django.http.QueryDict
类__setitem__
,该类实现了包括、和__delitem__
在内的一整套变异方法。它通过在调用其中一种突变方法时检查标志来实现不变性。当您调用该方法时,您将获得另一个启用了可变标志的实例。pop
clear
copy
QueryDict
为了提高性能?否:QueryDict
当可变标志关闭时,该类不会获得性能优势。
这样该POST
对象可以用作字典键吗?否:QueryDict
对象不可散列。
如此处所述,以便可以懒惰POST
地构建数据(无需承诺阅读整个响应)?我在代码中没有看到这方面的证据:据我所知,整个响应总是被读取,或者直接读取,或者通过响应读取。MultiPartParser
multipart
保护您免受编程错误的影响?我已经看到了这种说法,但是我从来没有很好地解释过这些错误是什么,以及不变性如何保护您免受它们的侵害。
无论如何,POST
它并不总是不可变的:当响应为 时multipart
,则POST
它是可变的。这似乎对你可能想到的大多数理论提出了质疑。(除非这种行为是疏忽。)
总之,我看不出在 Django 中POST
对象对于非multipart
请求是不可变的明确理由。
如果请求是 Djangoform
提交的结果,那么 POSTimmutable
确保表单提交和表单验证之间数据的完整性是合理的。但是,如果请求不是通过 Django提交发送的,那么 POST 就是因为没有表单验证。form
mutable
你总是可以做这样的事情:(根据@leo-the-manic 的评论)
# .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
更新:
Gareth Rees 是对的,第 1 点和第 3 点在这种情况下无效。虽然我认为第 2 点和第 4 点仍然有效,但我将把这些留在这里。
(我注意到 Pyramid(Pylon) 和 Django 的对象request.POST
都是MultiDict
.request.POST
我不能代表 Django 的人说话,尽管在我看来它可能是因为以下一些原因:
QueryDict
:正如 Gareth Rees 指出的那样,情况并非如此request.POST
,似乎服务器端的任何活动都不需要更改请求的数据。因此不可变对象更适合,更不用说它们具有实质性的性能优势。dict
键,我想这在 Django 中的某个地方可能非常有用。request.POST
(尤其是传递给第三方插件和输出)时,您可以期望来自用户的这个请求对象将保持不变。在某种程度上,这些原因也是“不可变 vs 可变?”的通用答案。问题。我敢肯定,在 Django 案例中,设计考虑因素比上述要多得多。
我喜欢它默认是不可变的。正如所指出的,如果需要,您可以使其可变,但您必须明确说明它。这就像“我知道我可以让我的表单调试成为一场噩梦,但我知道我现在在做什么。”
我在 Stack Answer https://stackoverflow.com/a/2339963的评论中发现了这一点
并且它必须是不可变的,以便可以懒惰地构建它。副本强制获取所有 POST 数据。直到副本,它可能不会全部被提取。此外,为了让多线程 WSGI 服务器工作得相当好,如果它是不可变的会很有帮助
请注意:multipart
自 Django 1.11
https://github.com/django/django/blob/stable/1.11.x/django/http/multipartparser.py#L292起,请求是不可变的
它们在以前的版本中是可变的。