mirror of
https://github.com/encode/django-rest-framework.git
synced 2025-08-02 11:30:12 +03:00
Add nest (multi-dimensional) field name support
This commit is contained in:
parent
315435d00a
commit
da13a0e481
|
@ -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
|
||||||
|
|
|
@ -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,
|
||||||
|
|
38
rest_framework/utils/datastructures.py
Executable file
38
rest_framework/utils/datastructures.py
Executable 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}
|
Loading…
Reference in New Issue
Block a user