django-rest-polymorphic icon indicating copy to clipboard operation
django-rest-polymorphic copied to clipboard

Automatic support for HyperlinkedModelSerializer?

Open infinitewarp opened this issue 7 years ago • 7 comments

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?

infinitewarp avatar Mar 19 '18 20:03 infinitewarp

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.

denisorehovsky avatar Mar 24 '18 12:03 denisorehovsky

this is fixed issue

auvipy avatar Nov 09 '19 06:11 auvipy

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

leogout avatar Dec 01 '20 13:12 leogout

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.

tomwojcik avatar Jul 07 '21 10:07 tomwojcik