Checklist
Steps to reproduce
Create a subclass of rest_framework.serializers.RelatedField that overrides to_representation such that it returns an unhashable type, such as a dict.
from rest_framework import serializers
class MyRelatedField(serializers.RelatedField):
def to_representation(self, obj):
return {
'id': obj.pk,
}
class MySerializer(serializers.Serializer):
related_field = MyRelatedField()
Use this Serializer in a view, then visit the view's endpoint in the browsable API.
Expected behavior
The page renders.
Actual behavior
An uncaught exception is thrown:
TypeError: unhashable type: 'dict'
(44 additional frame(s) were not displayed)
...
File "rest_framework/templatetags/rest_framework.py", line 91, in render_field
return renderer.render_field(field, style)
File "rest_framework/renderers.py", line 350, in render_field
return template_render(template, context)
File "rest_framework/compat.py", line 332, in template_render
return template.render(context, request=request)
File "rest_framework/relations.py", line 204, in iter_options
self.get_choices(cutoff=self.html_cutoff),
File "rest_framework/relations.py", line 191, in get_choices
for item in queryset
TypeError: unhashable type: 'dict'
Additional notes
This is caused by the change in #4379 .
We are currently working around the issue by overriding get_choices. Since there is no hook to format the keys in the return value, we had to copy and paste RelatedField's implmentation.
class MyRelatedField(serializers.RelatedField):
def to_representation(self, obj):
return {
'id': obj.pk,
}
# Below code is copied from rest_framework.serializers.RelatedField
# because we need to override the keys in the return value
def get_choices(self, cutoff=None):
queryset = self.get_queryset()
if queryset is None:
# Ensure that field.choices returns something sensible
# even when accessed with a read-only field.
return {}
if cutoff is not None:
queryset = queryset[:cutoff]
return OrderedDict([
(
# This is the only line that differs
# from the RelatedField's implementation
item.pk,
self.display_value(item)
)
for item in queryset
])
One possible solution would be to expose a hook to format the keys of the returned dictionary (like display_value, except for the keys).
Checklist
masterbranch of Django REST framework.Steps to reproduce
Create a subclass of
rest_framework.serializers.RelatedFieldthat overridesto_representationsuch that it returns an unhashable type, such as adict.Use this
Serializerin a view, then visit the view's endpoint in the browsable API.Expected behavior
The page renders.
Actual behavior
An uncaught exception is thrown:
Additional notes
This is caused by the change in #4379 .
We are currently working around the issue by overriding
get_choices. Since there is no hook to format the keys in the return value, we had to copy and paste RelatedField's implmentation.One possible solution would be to expose a hook to format the keys of the returned dictionary (like
display_value, except for the keys).