django-rest-polymorphic
django-rest-polymorphic copied to clipboard
Automatic support for HyperlinkedModelSerializer?
By default, django-rest-polymorphic doesn't play well with DRF's HyperlinkedModelSerializer class. For example, using the example project in this repo as a base project, if you replace each of the serializers.ModelSerializers with serializers.HyperlinkedModelSerializer and add 'url' to the fields list for each model, then the app crashes whenever it attempts to serialized the responses.
Here's the stack trace after I've posted the example in the docs (http POST "http://localhost:8000/projects/" resourcetype="ArtProject" topic="Guernica" artist="Picasso") or try to get the current list of projects (http GET "http://localhost:8000/projects/") after posting at least once:
Internal Server Error: /projects/
Traceback (most recent call last):
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/relations.py", line 376, in to_representation
url = self.get_url(value, self.view_name, request, format)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/relations.py", line 314, in get_url
return self.reverse(view_name, kwargs=kwargs, request=request, format=format)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/reverse.py", line 50, in reverse
url = _reverse(viewname, args, kwargs, request, format, **extra)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/reverse.py", line 63, in _reverse
url = django_reverse(viewname, args=args, kwargs=kwargs, **extra)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/urls/base.py", line 88, in reverse
return iri_to_uri(resolver._reverse_with_prefix(view, prefix, *args, **kwargs))
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/urls/resolvers.py", line 632, in _reverse_with_prefix
raise NoReverseMatch(msg)
django.urls.exceptions.NoReverseMatch: Reverse for 'artproject-detail' not found. 'artproject-detail' is not a valid view function or pattern name.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/core/handlers/exception.py", line 35, in inner
response = get_response(request)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/core/handlers/base.py", line 128, in _get_response
response = self.process_exception_by_middleware(e, request)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/core/handlers/base.py", line 126, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/viewsets.py", line 95, in view
return self.dispatch(request, *args, **kwargs)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/views.py", line 494, in dispatch
response = self.handle_exception(exc)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/views.py", line 454, in handle_exception
self.raise_uncaught_exception(exc)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/views.py", line 491, in dispatch
response = handler(request, *args, **kwargs)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/mixins.py", line 48, in list
return Response(serializer.data)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/serializers.py", line 742, in data
ret = super(ListSerializer, self).data
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/serializers.py", line 262, in data
self._data = self.to_representation(self.instance)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/serializers.py", line 660, in to_representation
self.child.to_representation(item) for item in iterable
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/serializers.py", line 660, in <listcomp>
self.child.to_representation(item) for item in iterable
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_polymorphic/serializers.py", line 58, in to_representation
ret = serializer.to_representation(instance)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/serializers.py", line 504, in to_representation
ret[field.field_name] = field.to_representation(attribute)
File "/Users/brasmith/.virtualenvs/drf/lib/python3.6/site-packages/rest_framework/relations.py", line 391, in to_representation
raise ImproperlyConfigured(msg % self.view_name)
django.core.exceptions.ImproperlyConfigured: Could not resolve URL for hyperlinked relationship using view name "artproject-detail". You may have failed to include the related model in your API, or incorrectly configured the `lookup_field` attribute on this field.
After seeing this in the stack trace:
django.urls.exceptions.NoReverseMatch: Reverse for 'artproject-detail' not found. 'artproject-detail' is not a valid view function or pattern name.
I realized I could fix this in each of the individual serializer classes by adding extra_kwargs to the Meta inner class like this:
extra_kwargs = {
'url': {'view_name': 'project-detail', 'lookup_field': 'pk'},
}
How difficult would it be to add this behavior automatically to serializer classes that are mapped together in a PolymorphicSerializer but extend HyperlinkedModelSerializer instead of ModelSerializer?
I'm not using hyperlinked models so I didn't even know about this bug. I don't know how difficult would it be for now, but we should try to fix it.
this is fixed issue
Maybe it has been fixed in the past, but I am facing the same issue as of today with
django-rest-polymorphic==0.1.9
djangorestframework==3.12.2
django==3.1.3
I confirm the bug persists, although a quick fix for me was to change the basename to what it required.
djangorestframework==3.11.1
django-rest-polymorphic==0.1.9
django-polymorphic==3.0.0
django==3.1.2
I named my model MyModelThing. Initially, the basename was thing-mymodel and I passed
extra_kwargs = {
'url': {'view_name': 'thing-mymodel-detail', 'lookup_field': 'pk'},
}
which failed but I found it was looking for mymodelthing-detail. And it works without passing any extra_kwargs.