Skip to content

Instantly share code, notes, and snippets.

@SmileyChris
Last active August 29, 2015 14:10
Show Gist options
  • Save SmileyChris/6be4815cf5751a4ae9ed to your computer and use it in GitHub Desktop.
Save SmileyChris/6be4815cf5751a4ae9ed to your computer and use it in GitHub Desktop.
import re
array_qs = re.compile(r'(\w+)\[(\d*)\]$')
class UnPHPify(object):
def process_request(self, request):
"""
Iterate request.GET, request.POST and request.FILES and amend the dict
with lists for any PHP-style arrays.
"""
self.process_request_attr(request, 'GET')
self.process_request_attr(request, 'POST')
self.process_request_attr(request, 'FILES')
def process_request_attr(self, request, attr):
multi_value_dict = getattr(request, attr)
if not multi_value_dict:
return
# request.GET and .POST are QueryDicts that are usually immutable.
immutable = not getattr(multi_value_dict, '_mutable', True)
new_dict = self.process_multi_value_dict(multi_value_dict, immutable)
if not new_dict:
return
if immutable:
multi_value_dict._mutable = False
setattr(request, attr, multi_value_dict)
def process_multi_value_dict(self, multi_value_dict, immutable=False):
"""
Add keys to the dictionary containing lists if PHP-style arrays are
found in the multi-value dictionary.
Processes both indexed ("names[2]") and unordered ("aliases[]") arrays.
For example::
>>> from django.request import QueryDict
>>> q = QueryDict('names[2]=chris&names[1]=joe', mutable=True)
>>> UnPHPify().process_multi_value_dict(q).getlist('names')
['joe', 'chris']
"""
indexed_lists = {}
unindexed_lists = {}
for key, value in multi_value_dict.items():
match = array_qs.match(key)
if not match:
continue
name, index = match.groups()
# If the un-arrayed name exists already in the dict, skip it.
if name in multi_value_dict:
continue
if index:
indexed_list = indexed_lists.getdefault(name, {})
indexed_list[int(index)] = value
else:
unindexed_list = unindexed_lists.getdefault(name, [])
unindexed_list.append(value)
if not indexed_lists and not unindexed_lists:
return
if immutable:
multi_value_dict = multi_value_dict.copy()
# First, iterate the indexed lists and make lists of the correct length
# then populate them with the indexed array values.
for name, ordered_values in indexed_lists.items():
new_list = unindexed_lists.getdefault(name, [])
extra = max(ordered_values) - len(new_list)
if extra > 0:
new_list += [None] * extra
for index, value in ordered_values.items():
new_list[index] = value
# Now fill the dictionary with all populated lists.
for name, new_list in unindexed_lists.items():
multi_value_dict.setlist(name, new_list)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment