136
It’s a bit of a mystery, isn’t it? Several superficially plausible theories turn out to be wrong on investigation:
-
So that the
POST
object doesn’t have to implement mutation methods? No: thePOST
object belongs to thedjango.http.QueryDict
class, which implements a full set of mutation methods including__setitem__
,__delitem__
,pop
andclear
. It implements immutability by checking a flag when you call one of the mutation methods. And when you call thecopy
method you get anotherQueryDict
instance with the mutable flag turned on. -
For performance improvement? No: the
QueryDict
class gains no performance benefit when the mutable flag is turned off. -
So that the
POST
object can be used as a dictionary key? No:QueryDict
objects are not hashable. -
So that the
POST
data can be built lazily (without committing to read the whole response), as claimed here? I see no evidence of this in the code: as far as I can tell, the whole of the response is always read, either directly, or viaMultiPartParser
formultipart
responses. -
To protect you against programming errors? I’ve seen this claimed, but I’ve never seen a good explanation of what these errors are, and how immutability protects you against them.
In any case, POST
is not always immutable: when the response is multipart
, then POST
is mutable. This seems to put the kibosh on most theories you might think of. (Unless this behaviour is an oversight.)
In summary, I can see no clear rationale in Django for the POST
object to be immutable for non-multipart
requests.
88
If the request was the result of a Django form
submission, then it is reasonable for POST being immutable
to ensure the integrity of the data between the form submission and the form validation. However, if the request was not sent via a Django form
submission, then POST is mutable
as there is no form validation.
You can always do something like this: (as per @leo-the-manic’s comment)
# .....
mutable = request.POST._mutable
request.POST._mutable = True
request.POST['some_data'] = 'test data'
request.POST._mutable = mutable
# ......
- [Django]-How to compare two JSON objects with the same elements in a different order equal?
- [Django]-How do I POST with jQuery/Ajax in Django?
- [Django]-H14 error in heroku – "no web processes running"
5
Update:
Gareth Rees was right that point 1 & 3 were not valid in this case. Though I think point 2 and 4 are still valid, therefore I will leave theses here.
(I noticed that the request.POST
object of both Pyramid(Pylon) and Django is some form of MultiDict
. So perhaps it is a more common practice than making request.POST
immutable.)
I can’t speak for the Django guys, though it seems to me that it could because of some of these reasons:
Performence. immutable objects are “faster” over mutable ones in that they allow substantial optimizations. An object is immutable means that we can allocate space for it at creation time, and the space requirements are not changing. It also has things like copy efficiency and comparison efficiency because of it.
Edit: this is not the case forQueryDict
as Gareth Rees pointed out.- In the case of
request.POST
, it seems no activity in the server side should need to alter the request’s data. And hence immutable objects are more suited, not to mention they have substantial performence advantage. Immutable objects can be used asdict
keys, which I suppose could be very useful somewhere in Django..
Edit: my mistake, immutable does not directly imply hashable; hashable objects however, are typically immutable as well.- When you pass around
request.POST
(especially to third-party plugins and out), you can expect that this request object from the user will remain unchanged.
In some way these reasons are also generic answers to “immutable vs mutable?” question. I am certain there are much more design considerations than above in the Django case.
- [Django]-Django set default form values
- [Django]-How can I get all the request headers in Django?
- [Django]-Django – How to use decorator in class-based view methods?
4
I like it being immutable by default.
As pointed out you can make it mutable if you need to but you must be explicit about it.
It is like ‘I know that I can make my form debugging a nightmare but I know what I am doing now.’
- [Django]-Django: Fat models and skinny controllers?
- [Django]-Django – Circular model import issue
- [Django]-Django: How do I add arbitrary html attributes to input fields on a form?
2
I found this in a comment on Stack Answer 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]-Dynamic choices field in Django Models
- [Django]-Django: accessing session variables from within a template?
- [Django]-ValueError: The field admin.LogEntry.user was declared with a lazy reference
1
Please note: multipart
request are immutable since Django 1.11
https://github.com/django/django/blob/stable/1.11.x/django/http/multipartparser.py#L292
They were mutable in previous versions.
- [Django]-Django Cache cache.set Not storing data
- [Django]-How to access the local Django webserver from outside world
- [Django]-Django: How to check if the user left all fields blank (or to initial values)?