-
-
Notifications
You must be signed in to change notification settings - Fork 7k
Closed
Description
Checklist
- I have verified that that issue exists against the
masterbranch of Django REST framework. - I have searched for similar issues in both open and closed tickets and cannot find a duplicate. --> Aspects of this issue are documented in app/json VS querystring request leads to different data representations #1593 and Unit tests using APIClient
request.DATAdo not use a QueryDict. #3347 but I wanted to provide a proper root cause analysis - This is not a usage question. (Those should be directed to the discussion group instead.)
- This cannot be dealt with as a third party library. (We prefer new functionality to be in the form of third party libraries where possible.)
- I have reduced the issue to the simplest possible case.
- I have included a failing test as a pull request. (If you are unable to do so we can still accept the issue.)
Steps to reproduce
- Have an API view that you can POST a list of elements to, e.g. with a list of file attachments or maybe a multi-selection box in a
ModelViewSet.perform_create - access the items via
self.request.data.getlist('items', [])
Expected behavior
A list of items or an empty list should be returned, regardless of the Content-type used to call the API.
Actual behavior
The view only works on form-data (x-www-form-urlencoded) uploads, JSON uploads lead to an exception:
Traceback (most recent call last):
File "/srv/myapp-dev/lib/python3.7/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/srv/myapp-dev/lib/python3.7/site-packages/django/core/handlers/base.py", line 179, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/srv/myapp-dev/lib/python3.7/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/viewsets.py", line 125, in view
return self.dispatch(request, *args, **kwargs)
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/srv/myapp-dev/lib/python3.7/site-packages/rest_framework/mixins.py", line 19, in create
self.perform_create(serializer)
File "/srv/myapp-dev/app/app/apis.py", line 597, in perform_create
items = self.request.data.getlist('items', [])
AttributeError: 'dict' object has no attribute 'getlist'
As unit tests use form-data by default, and most modern apps use JSON, this leads to a bug that won't be detected until rolled out to a live server.
Parser Inconsistency
The reason is that FormParser returns an (immutable) QueryDict whereas JSONParser returns the dict response obtained from json.loads().
The most reasonable way to achieve consistency would be to make JSONParser also return a QueryDict, e.g. using this conversion:
parsed_dict = json.load(decoded_stream, parse_constant=parse_constant)
query_dict = QueryDict('', mutable=True)
query_dict.update(parsed_dict)
query_dict._mutable = False # set to immutable to match FormParser
return query_dictMetadata
Metadata
Assignees
Labels
No labels