关于django:django – 为什么request.POST对象是不可变的?

django - why is the request.POST object immutable?

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

我知道你可以通过复制一份邮寄数据来破坏它

1
post = request.POST.copy()

但为什么要这样做?当然,仅仅允许事物是可变的会更简单些吗?还是因为其他原因使用,可能导致问题?


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

  • 所以POST对象不必实现突变方法?否:POST对象属于django.http.QueryDict类,实现了包括__setitem____delitem__popclear等一整套突变方法。它通过在调用其中一个突变方法时检查标志来实现不变性。当您调用copy方法时,会得到另一个QueryDict实例,该实例的可变标志已打开。

  • 为了提高绩效?否:关闭可变标志时,QueryDict类不会获得性能优势。

  • 这样,POST对象就可以用作字典键了?否:QueryDict对象不可哈希。

  • 因此,可以像这里所说的那样,延迟地构建POST数据(而不承诺读取整个响应)?我在代码中看不到这方面的证据:据我所知,整个响应始终是直接读取的,或者通过MultiPartParser读取multipart响应。

  • 为了防止编程错误?我见过这个声明,但是我从来没有看到过一个很好的解释,这些错误是什么,以及不可变如何保护您免受它们的影响。

  • 在任何情况下,POST并不总是不变的:当响应为multipart时,POST是可变的。这似乎使你所想到的大多数理论都有点模棱两可。(除非这种行为是一种监督。)

    综上所述,Django没有明确的理由认为POST反对非multipart请求不可变。


    如果该请求是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案例中,有比上面更多的设计考虑。


    我喜欢它在默认情况下是不变的。正如所指出的,如果需要的话,您可以使它变为可变的,但您必须明确地说明这一点。这就像"我知道我可以让窗体调试成为一场噩梦,但我知道我现在在做什么"。


    我在堆栈回答的评论中找到了这个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

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