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

正如标题所要求的那样,为什么Django人决定用querydict实现request.POST对象(当然,这反过来又使得整个事物不可变?)

我知道你可以通过制作一份发布数据来复制它

post = request.POST.copy() 

但为什么呢? 无论如何,只要让事情变得可变,肯定会更简单。 或者它也被用于其他一些可能导致问题的原因?

这有点神秘,不是吗? 几个表面上看似是而非的理论在调查中是错误的:

  1. 这样POST对象不必实现突变方法? No: POST对象属于django.http.QueryDict类 ,它实现了一套完整的突变方法,包括__setitem__ django.http.QueryDictdjango.http.QueryDictpopclear 。 当你调用一个突变方法时,它通过检查一个标志来实现不变性。 而当你调用copy方法时,你会得到另一个QueryDict实例的可变标志打开。

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

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

  4. 这样, POST数据可以build立懒惰(没有承诺读取整个响应), 在这里声称 ? 在代码中我没有看到这样的证据:据我所知,整个响应总是直接读取,或通过MultiPartParser读取multipart响应。

  5. 为了防止编程错误? 我已经看到这个声明,但是我从来没有看到这些错误是什么的一个很好的解释,以及不变性如何保护你。

在任何情况下, POST 并不总是不可变的 :当响应是multipartPOST是可变的。 这似乎把基布斯放在你可能想到的大多数理论上。 (除非这种行为是疏忽)

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

如果请求是Django form提交的结果,那么POST是immutable以确保表单提交和表单validation 之间的数据完整性。 但是,如果请求不是通过Django form提交发送的,那么POST是mutable因为没有表单validation。

你总是可以这样做:(根据@ 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是无效的。 虽然我认为第二点和第四点仍然有效,所以我将在这里留下这些论点。

(我注意到Pyramid(Pylon)和Django的request.POST对象都是MultiDict一种forms,所以也许这是比request.POST更普遍的做法, MultiDict不可改变。)


我不能代表Django的人,尽pipe在我看来,这可能是由于以下原因:

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

在某些方面,这些原因也是对“不可变与可变”的通用答案。 题。 我确信在Django案例中有更多的devise考虑。

我发现这在评论堆栈回答https://stackoverflow.com/a/2339963

它必须是不可改变的,以便它可以懒散地build造。 复制力量获取所有POST数据。 直到副本,它可能不会被全部取出。 而且,对于一个multithreading的WSGI服务器来说,如果这个工作是不可变的,那么这个服务器将会很有帮助

我喜欢它默认是不可变的。 正如你所指出的那样,如果你需要,你可以使它变得可变,但是你必须明确它。 这就像'我知道我可以让我的formsdebugging噩梦,但我知道我现在在做什么。