Key error while building raw_data_form for a PUT request on ModelSerializer with extra field added in to_representation · Issue #5498 · encode/django-rest-framework (original) (raw)

Checklist

#5259

Steps to reproduce

This happens on 3.6.4 onwards

  1. Override to_representation of a ModelSerializer to include an extra field (that does not exist in the ModelSerializer) e.g.
def to_representation(self, instance):
    output = ModelSerializer.to_representation(self, instance)
    output['meta_name'] = self.__class__.Meta.model.__name__
    return output
  1. Create a GenericAPI view on this ModelSerilizer and allow GET and PUT method on it
  2. Make a GET request to this view via Browsable API

Expected behavior

We should get serialized data as well as a PUT form. This was the case till 3.6.3 but not after #5259. In this fix a check was added to eliminate HiddenFields in the serializer while serializing for raw data form, but we should ensure that a 'field' is a real field before checking if it is a HiddenField

Actual behavior

We get a KeyError on line 560 in rest_framework/renderers.py while building the raw form for PUT as 'meta_name' is actually not a field in the serializer but just added in to-representation

Stack trace:

Environment:

Request Method: GET
Request URL: /api/nextvisit/217/

Django Version: 1.10.5
Python Version: 3.5.2
Installed Applications:
['django.contrib.admin',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'bootstrap4',
 'rest_framework',
 'clinic']
Installed Middleware:
['django.middleware.security.SecurityMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.common.CommonMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.middleware.clickjacking.XFrameOptionsMiddleware']

Traceback:

File "/lib/python3.5/site-packages/django/core/handlers/exception.py" in inner 39. response = get_response(request)

File "/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 217. response = self.process_exception_by_middleware(e, request)

File "/lib/python3.5/site-packages/django/core/handlers/base.py" in _get_response 215. response = response.render()

File "/lib/python3.5/site-packages/django/template/response.py" in render 109. self.content = self.rendered_content

File "/lib/python3.5/site-packages/rest_framework/response.py" in rendered_content 72. ret = renderer.render(self.data, accepted_media_type, context)

File "/lib/python3.5/site-packages/rest_framework/renderers.py" in render 706. context = self.get_context(data, accepted_media_type, renderer_context)

File "/lib/python3.5/site-packages/rest_framework/renderers.py" in get_context 640. raw_data_put_form = self.get_raw_data_form(data, view, 'PUT', request)

File "/lib/python3.5/site-packages/rest_framework/renderers.py" in get_raw_data_form 559. data = {k: v for (k, v) in serializer.data.items()

File "/lib/python3.5/site-packages/rest_framework/renderers.py" in 560. if not isinstance(serializer.fields[k],

File "/lib/python3.5/site-packages/rest_framework/utils/serializer_helpers.py" in getitem 148. return self.fields[key]

Exception Type: KeyError at /api/nextvisit/217/ Exception Value: 'meta_name'


Edited for formatting (@rpkilby)