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.multipartparser import parse_header
|
||||
from django.utils.datastructures import MultiValueDict
|
||||
from rest_framework.utils.datastructures import DotExpandedDict
|
||||
from rest_framework import HTTP_HEADER_ENCODING
|
||||
from rest_framework import exceptions
|
||||
from rest_framework.compat import BytesIO
|
||||
|
@ -152,6 +153,10 @@ class Request(object):
|
|||
"""
|
||||
if not _hasattr(self, '_data'):
|
||||
self._load_data_and_files()
|
||||
|
||||
if api_settings.NESTED_FIELDS:
|
||||
self._data = DotExpandedDict(self._data)
|
||||
|
||||
return self._data
|
||||
|
||||
@property
|
||||
|
|
|
@ -65,6 +65,10 @@ DEFAULTS = {
|
|||
'anon': None,
|
||||
},
|
||||
|
||||
# Nested (multi-dimensional) field names
|
||||
'NESTED_FIELDS': False,
|
||||
'NESTED_FIELD_TOKENIZER': '.',
|
||||
|
||||
# Pagination
|
||||
'PAGINATE_BY': 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