112

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

我知道你可以通过复制帖子数据来修改它

post = request.POST.copy()

但为什么要这样做?当然,无论如何允许事物是可变的会更简单吗?或者它是否也被用于其他可能导致问题的原因?

4

6 回答 6

135

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

  1. 这样POST对象就不必实现变异方法了吗?否:该POST对象属于django.http.QueryDict__setitem__,该类实现了包括、和__delitem__在内的一整套变异方法。它通过在调用其中一种突变方法时检查标志来实现不变性。当您调用该方法时,您将获得另一个启用了可变标志的实例。popclearcopyQueryDict

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

  3. 这样该POST对象可以用作字典键吗?否:QueryDict对象不可散列。

  4. 如此处所述,以便可以懒惰POST地构建数据(无需承诺阅读整个响应)?我在代码中没有看到这方面的证据:据我所知,整个响应总是被读取,或者直接读取,或者通过响应读取。MultiPartParsermultipart

  5. 保护您免受编程错误的影响?我已经看到了这种说法,但是我从来没有很好地解释过这些错误是什么,以及不变性如何保护您免受它们的侵害。

无论如何,POST并不总是不可变的:当响应为 时multipart,则POST它是可变的。这似乎对你可能想到的大多数理论提出了质疑。(除非这种行为是疏忽。)

总之,我看不出在 Django 中POST对象对于非multipart请求是不可变的明确理由。

于 2012-09-27T10:54:56.773 回答
86

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

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

#  .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
于 2014-01-21T15:25:45.287 回答
5

更新

Gareth Rees 是对的,第 1 点和第 3 点在这种情况下无效。虽然我认为第 2 点和第 4 点仍然有效,但我将把这些留在这里。

(我注意到 Pyramid(Pylon) 和 Django 的对象request.POST都是MultiDict.request.POST


我不能代表 Django 的人说话,尽管在我看来它可能是因为以下一些原因:

  1. 性能。不可变对象比可变对象“更快”,因为它们允许大量优化。对象是不可变的,意味着我们可以在创建时为其分配空间,并且空间需求不会发生变化。它也因此具有复制效率和比较效率之类的东西。 编辑QueryDict:正如 Gareth Rees 指出的那样,情况并非如此
  2. 在 的情况下request.POST,似乎服务器端的任何活动都不需要更改请求的数据。因此不可变对象更适合,更不用说它们具有实质性的性能优势。
  3. 不可变对象可以用作dict键,我这在 Django 中的某个地方可能非常有用。 编辑:我的错误,不可变并不直接暗示可散列然而,可散列对象通常也是不可变的。
  4. 当您传递request.POST(尤其是传递给第三方插件和输出)时,您可以期望来自用户的这个请求对象将保持不变。

在某种程度上,这些原因也是“不可变 vs 可变?”的通用答案。问题。我敢肯定,在 Django 案例中,设计考虑因素比上述要多得多。

于 2012-09-27T01:55:59.653 回答
4

我喜欢它默认是不可变的。正如所指出的,如果需要,您可以使其可变,但您必须明确说明它。这就像“我知道我可以让我的表单调试成为一场噩梦,但我知道我现在在做什么。”

于 2015-03-17T15:24:13.820 回答
2

我在 Stack Answer https://stackoverflow.com/a/2339963的评论中发现了这一点

并且它必须是不可变的,以便可以懒惰地构建它。副本强制获取所有 POST 数据。直到副本,它可能不会全部被提取。此外,为了让多线程 WSGI 服务器工作得相当好,如果它是不可变的会很有帮助

于 2014-04-30T22:40:43.527 回答
1

请注意:multipart自 Django 1.11 https://github.com/django/django/blob/stable/1.11.x/django/http/multipartparser.py#L292起,请求是不可变的

它们在以前的版本中是可变的。

于 2018-04-12T10:40:07.290 回答