Skip to content

Type of request.data inconsistent (dict / QueryDict) depending on request content-type #7633

@ge0rg

Description

@ge0rg

Checklist

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_dict

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions