From 4e0b3ad1b70f932dbe3751573ca1b52710bb6b80 Mon Sep 17 00:00:00 2001 From: Dan Stephenson Date: Fri, 6 Sep 2013 00:43:29 +0100 Subject: [PATCH] Moving of nested form tokenization into parsers, plus some minor function naming changes --- rest_framework/parsers.py | 16 ++++++++++++++++ rest_framework/request.py | 12 +++--------- rest_framework/utils/datastructures.py | 6 +++--- 3 files changed, 22 insertions(+), 12 deletions(-) diff --git a/rest_framework/parsers.py b/rest_framework/parsers.py index 25be2e6ab..60080b29b 100644 --- a/rest_framework/parsers.py +++ b/rest_framework/parsers.py @@ -13,6 +13,8 @@ from django.http.multipartparser import MultiPartParserError, parse_header, Chun from rest_framework.compat import yaml, etree from rest_framework.exceptions import ParseError from rest_framework.compat import six +from rest_framework.utils.datastructures import TokenExpandedDict +from rest_framework.settings import api_settings import json import datetime import decimal @@ -40,6 +42,16 @@ class BaseParser(object): """ raise NotImplementedError(".parse() must be overridden.") + def _parse_tokenization(self, data): + """ + Configuration dependant processing of input data, where character tokens + (such as periods '.') can be used to reshape for data into nested form, + for use with NestedModelSerializer. + """ + if api_settings.NESTED_FIELDS: + data = TokenExpandedDict(data) + return data + class JSONParser(BaseParser): """ @@ -108,6 +120,8 @@ class FormParser(BaseParser): parser_context = parser_context or {} encoding = parser_context.get('encoding', settings.DEFAULT_CHARSET) data = QueryDict(stream.read(), encoding=encoding) + data = self._parse_tokenization(data) + return data @@ -134,6 +148,8 @@ class MultiPartParser(BaseParser): try: parser = DjangoMultiPartParser(meta, stream, upload_handlers, encoding) data, files = parser.parse() + data = self._parse_tokenization(data) + return DataAndFiles(data, files) except MultiPartParserError as exc: raise ParseError('Multipart form parse error - %s' % six.u(exc)) diff --git a/rest_framework/request.py b/rest_framework/request.py index 45d1a43e8..b08eb9939 100644 --- a/rest_framework/request.py +++ b/rest_framework/request.py @@ -13,7 +13,6 @@ 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 @@ -151,12 +150,8 @@ class Request(object): Similar to usual behaviour of `request.POST`, except that it handles arbitrary parsers, and also works on methods other than POST (eg PUT). """ - if not _hasattr(self, '_data'): - self._load_data_and_files() - - if api_settings.NESTED_FIELDS: - self._data = DotExpandedDict(self._data) - + #if not _hasattr(self, '_data'): + # self._load_data_and_files() return self._data @property @@ -282,8 +277,7 @@ class Request(object): return # At this point we're committed to parsing the request as form data. - self._data = self._request.POST - self._files = self._request.FILES + self._data, self._files = self._parse() # Method overloading - change the method and remove the param from the content. if (self._METHOD_PARAM and diff --git a/rest_framework/utils/datastructures.py b/rest_framework/utils/datastructures.py index b7bb3466b..57012d1e7 100755 --- a/rest_framework/utils/datastructures.py +++ b/rest_framework/utils/datastructures.py @@ -4,13 +4,13 @@ Utility functions for reshaping datastructures from rest_framework.settings import api_settings from django.http import QueryDict -class DotExpandedDict(QueryDict): +class TokenExpandedDict(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'], \ + >>> d = TokenExpandedDict({'person.1.firstname': ['Simon'], \ 'person.1.lastname': ['Willison'], \ 'person.2.firstname': ['Adrian'], \ 'person.2.lastname': ['Holovaty']}) @@ -22,7 +22,7 @@ class DotExpandedDict(QueryDict): {'lastname': ['Willison'], 'firstname': ['Simon']} # Gotcha: Results are unpredictable if the dots are "uneven": - >>> DotExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1}) + >>> TokenExpandedDict({'c.1': 2, 'c.2': 3, 'c': 1}) {'c': 1} """ def __init__(self, key_to_list_mapping):