Skip to content

Commit

Permalink
Merge pull request #41 from AltSchool/feature/replace-mergedict
Browse files Browse the repository at this point in the history
Convert request.data from MergeDict to dict when data ends up being a
  • Loading branch information
ryochiji committed Oct 2, 2015
2 parents 035608e + b8d4bdd commit 8778e40
Show file tree
Hide file tree
Showing 4 changed files with 67 additions and 4 deletions.
2 changes: 1 addition & 1 deletion dynamic_rest/__init__.py
Original file line number Diff line number Diff line change
@@ -1 +1 @@
__version__ = "1.2.5"
__version__ = "1.2.6"
19 changes: 17 additions & 2 deletions dynamic_rest/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from django.conf import settings
from django.http import QueryDict
from django.utils.datastructures import MergeDict

from rest_framework import viewsets, exceptions
from rest_framework.exceptions import ValidationError
Expand Down Expand Up @@ -72,12 +73,26 @@ def initialize_request(self, request, *args, **kargs):
"""
Override DRF initialize_request() method to swap request.GET
(which is aliased by request.QUERY_PARAMS) with a mutable instance
of QueryParams.
of QueryParams, and to convert request MergeDict to a subclass of dict
for consistency (MergeDict is not a subclass of dict)
"""
request.GET = QueryParams(request.GET)
return super(WithDynamicViewSetMixin, self).initialize_request(

request = super(WithDynamicViewSetMixin, self).initialize_request(
request, *args, **kargs)

# MergeDict doesn't have the same API as dict.
# Django has deprecated MergeDict and DRF is moving away from
# using it - thus, were comfortable replacing it with a QueryDict
# This will allow the data property to have normal dict methods.
if isinstance(request._full_data, MergeDict):
data_as_dict = request.data.dicts[0]
for d in request.data.dicts[1:]:
data_as_dict.update(d)
request._full_data = data_as_dict

return request

def get_request_feature(self, name):
"""Parses the request for a particular feature.
Expand Down
28 changes: 27 additions & 1 deletion tests/test_viewsets.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,11 @@
from rest_framework import exceptions
from rest_framework.request import Request
from dynamic_rest.filters import DynamicFilterBackend, FilterNode
from tests.viewsets import UserViewSet
from tests.setup import create_fixture
from tests.viewsets import (
GroupNoMergeDictViewSet,
UserViewSet
)
from tests.serializers import GroupSerializer


Expand Down Expand Up @@ -116,3 +120,25 @@ def testNestedFilterRewrite(self):
gs = GroupSerializer(include_fields='*')
filter_key = node.generate_query_key(gs)
self.assertEqual(filter_key, 'users__id__in')


class TestMergeDictConvertsToDict(TestCase):

def setUp(self):
self.fixture = create_fixture()
self.view = GroupNoMergeDictViewSet.as_view({'post': 'create'})
self.rf = RequestFactory()

def testMergeDictRequest(self):
data = {
'name': 'miao',
'random_input': [1, 2, 3]
}
# Django test submits data as multipart-form by default,
# which results in request.data being a MergeDict.
# Wrote UserNoMergeDictViewSet to raise an exception (return 400)
# if request.data ends up as MergeDict, is not a dict, or
# is a dict of lists.
request = Request(self.rf.post('/groups/', data))
response = self.view(request)
self.assertEqual(response.status_code, 201)
22 changes: 22 additions & 0 deletions tests/viewsets.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
from django.utils.datastructures import MergeDict

from rest_framework import exceptions

from dynamic_rest.viewsets import DynamicModelViewSet
from tests.serializers import (
CatSerializer,
Expand Down Expand Up @@ -40,6 +44,24 @@ def list(self, request, *args, **kwargs):
return super(UserViewSet, self).list(request, *args, **kwargs)


class GroupNoMergeDictViewSet(DynamicModelViewSet):
model = Group
serializer_class = GroupSerializer
queryset = Group.objects.all()

def create(self, request, *args, **kwargs):
if hasattr(request, 'data'):
if isinstance(request.data, MergeDict):
raise exceptions.ValidationError("request.data is MergeDict")
elif not isinstance(request.data, dict):
raise exceptions.ValidationError("request.data is not a dict")
return super(GroupNoMergeDictViewSet, self).create(
request,
*args,
**kwargs
)


class GroupViewSet(DynamicModelViewSet):
features = (
DynamicModelViewSet.INCLUDE, DynamicModelViewSet.EXCLUDE,
Expand Down

0 comments on commit 8778e40

Please sign in to comment.