Opened 9 years ago

Closed 9 years ago

Last modified 9 years ago

#25347 closed Cleanup/optimization (wontfix)

QueryDict can't return a list for a select multiple form element

Reported by: Jonathan Drake Owned by: nobody
Component: HTTP handling Version: dev
Severity: Normal Keywords:
Cc: Triage Stage: Unreviewed
Has patch: no Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description

I'm not sure why this is the case but QueryDict can't return a list object for a multi select unless you explicitly call getlist. I'm not sure why this is the case since it should be able to translate the POST or GET data into the proper data structures.

"In an HttpRequest object, the GET and POST attributes are instances of django.http.QueryDict, a dictionary-like class customized to deal with multiple values for the same key. This is necessary because some HTML form elements, notably <select multiple>, pass multiple values for the same key."

This is from the documentation and it mentions that this custom class around the post data is needed to support it, yet doesn't explain why it's needed. No other language or framework I've worked with has this limitation where you need to explicitly know the form element's "type" before hand. This makes dynamically parsing the results impossible since you need to know the type before you can actually access it correctly.

Further more I don't see how returning the last element of a list is helpful in any real use cases. Clearly the class knows which data type it is if it can properly access the list element.

Change History (7)

comment:1 by Tim Graham, 9 years ago

Could you include a failing test or a code snippet that demonstrates the expected vs. actual behavior?

comment:2 by Jonathan Drake, 9 years ago

I'm not sure how that's required. This isn't a bug but rather a limitation that I'm hoping can be fixed as a new feature.

If you iterate over request.POST, I'm expecting that getitem can handle giving me a list or a scalar depending on what was sent in the form data. Right now I have to know the actual key in order to extract the given key as a list so I don't end up with the last item in it.

The other alternative I have is to run getlist() on every single key and then iterate over scalars as if they are lists which just adds unneeded overhead. I guess I could also roll out my own request data parser to replace QueryDict, but it seems like this should be core functionality that QueryDict can get right itself.

Version 0, edited 9 years ago by Jonathan Drake (next)

comment:3 by Claude Paroz, 9 years ago

I recognize that this behavior is a bit awkward.
Now the question is: can we find a path to change this behavior without breaking lots of application code, as suddenly .get() can return lists or scalars? Is it worth a plain backwards incompatibility?

comment:4 by Claude Paroz, 9 years ago

Component: UncategorizedHTTP handling
Type: UncategorizedCleanup/optimization
Version: 1.8master

comment:5 by Tim Graham, 9 years ago

Proof of concept that allows QueryDict.get() return to list. If it doesn't get any immediate negative reaction, I'll raise this idea on the mailing list.

Last edited 9 years ago by Tim Graham (previous) (diff)

comment:6 by Simon Charette, 9 years ago

Resolution: wontfix
Status: newclosed

I think there's a good reason QueryDict.get() doesn't return a list if a key is specified multiple time (Compared to PHP's $_GET and $_POST) and it shouldn't be changed. Plus this is backward incompatible.

If I use self.request.GET.get('foo') I'm expecting a str to be returned and not a list. User controlled input shouldn't be allowed to change the return type of .get() and possibly introduce security issues.

e.g.

# This would work with ?pk=1 but cause a TypeError with ?pk=1&pk2
def view(request):
    pk = request.GET.get('pk')
    obj = Model.objects.get(pk=pk)

The same issue applies when using the Form api that relies on self.data.get.

This is from the documentation and it mentions that this custom class around the post data is needed to support it, yet doesn't explain why it's needed. No other language or framework I've worked with has this limitation where you need to explicitly know the form element's "type" before hand. This makes dynamically parsing the results impossible since you need to know the type before you can actually access it correctly.

You should know before hand, independently of the form element "type" used, if you're expecting a parameter to be a scalar or a list of element. For example, if get() was modified to return a list if a key is specified more than once it would still return a scalar if you selected only one element in a select[type=multiple].

Closing as wontfix since this is highly backward incompatible and would introduce a subtle foot-gun for newcomers.

comment:7 by Claude Paroz, 9 years ago

FWIW, Simon's explanation has convinced me, too :-)

Note: See TracTickets for help on using tickets.
Back to Top