Add nest (multi-dimensional) field name support

This commit is contained in:
Dan Stephenson 2013-08-26 15:40:23 +01:00
parent 315435d00a
commit da13a0e481
3 changed files with 47 additions and 0 deletions

View File

@ -13,6 +13,7 @@ from django.conf import settings
from django.http import QueryDict from django.http import QueryDict
from django.http.multipartparser import parse_header from django.http.multipartparser import parse_header
from django.utils.datastructures import MultiValueDict from django.utils.datastructures import MultiValueDict
from rest_framework.utils.datastructures import DotExpandedDict
from rest_framework import HTTP_HEADER_ENCODING from rest_framework import HTTP_HEADER_ENCODING
from rest_framework import exceptions from rest_framework import exceptions
from rest_framework.compat import BytesIO from rest_framework.compat import BytesIO
@ -152,6 +153,10 @@ class Request(object):
""" """
if not _hasattr(self, '_data'): if not _hasattr(self, '_data'):
self._load_data_and_files() self._load_data_and_files()
if api_settings.NESTED_FIELDS:
self._data = DotExpandedDict(self._data)
return self._data return self._data
@property @property

View File

@ -65,6 +65,10 @@ DEFAULTS = {
'anon': None, 'anon': None,
}, },
# Nested (multi-dimensional) field names
'NESTED_FIELDS': False,
'NESTED_FIELD_TOKENIZER': '.',
# Pagination # Pagination
'PAGINATE_BY': None, 'PAGINATE_BY': None,
'PAGINATE_BY_PARAM': None, 'PAGINATE_BY_PARAM': None,

View File

@ -0,0 +1,38 @@
"""
Utility functions for reshaping datastructures
"""
from rest_framework.settings import api_settings
from django.http import QueryDict
class DotExpandedDict(QueryDict):
"""
A special dictionary constructor that takes a dictionary in which the keys
may contain dots to specify inner dictionaries. It's confusing, but this
example should make sense.
>>> d = DotExpandedDict({'person.1.firstname': ['Simon'], \
'person.1.lastname': ['Willison'], \
'person.2.firstname': ['Adrian'], \
'person.2.lastname': ['Holovaty']})
>>> d
{'person': {'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}}
>>> d['person']
{'1': {'lastname': ['Willison'], 'firstname': ['Simon']}, '2': {'lastname': ['Holovaty'], 'firstname': ['Adrian']}}
>>> d['person']['1']
{'lastname': ['Willison'], 'firstname': ['Simon']}
# Gotcha: Results are unpredictable if the dots are "uneven":
>>> DotExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1})
{'c': 1}
"""
def __init__(self, key_to_list_mapping):
for k, v in key_to_list_mapping.items():
current = self
bits = k.split(api_settings.NESTED_FIELD_TOKENIZER)
for bit in bits[:-1]:
current = current.setdefault(bit, {})
# Now assign value to current position
try:
current[bits[-1]] = v
except TypeError: # Special-case if current isn't a dict.
current = {bits[-1]: v}