django-rest-polymorphic
django-rest-polymorphic copied to clipboard
Recursion error on __instancecheck__ when making sub-serializers inherit from a PolymorphicSerializer child
Hi everyone,
Here is my situation:
- In my Django models, I have a
ParentModel
class that inherits fromdjango-polymorphic
'sPolymorphicModel
.ParentModel
is also inherited by some children, such asChildModelA
,ChildModelB
, etc.ParentModel
is not abstract andChildModelA
,B
are not proxy models. I need this setup becauseParentModel
has attributes that I need to link to its children. When I runParentModel.objects.all()
in the console,django-polymorphic
behaves as expected and returns me a collection ofChildModelA
,ChildModelB
, etc., even if they actually inherit the "polymorphic traits" of the 2nd-level parent. - However,
django-rest-polymorphic
strikes me withRecursionError: maximum recursion depth exceeded in __instancecheck__
when I try to replicate this setup for my corresponding serializer classes. -
I realized that this is fixed by not making my children serializer classes inherit
ParentModelSerializer
, but that defeats the purpose of what I want to achieve. So, I don't know if what I'm asking for is a bug fix or a feature request.
Thank you in advance for your time.
Here is the code to clarify (field declarations are not accurate for the sake of simplicity):
- In the models file:
class ParentModel(PolymorphicModel):
attributeA = models.CharField()
attributeB = models.IntField()
class ChildModelA(ParentModel):
attributeC = models.ForeignKey()
attributeD = models.URLField()
class ChildModelB(ParentModel):
...
- When running
ParentModel.objects.all()
:
[<ChildModelA: ChildModelA object (3739843)>, <ChildModelB: ChildModelB object (3098393)>, ...]
- In the serializers file:
class ParentModelSerializer(serializers.ModelSerializer, PolymorphicSerializer):
attributeA = serializers.CharField()
attributeB = serializers.IntField()
class Meta:
model = ParentModel
fields = [
"attributeA",
"attributeB",
]
class ChildModelASerializer(ParentModelSerializer):
attributeC = serializers.HyperlinkedRelatedField()
attributeD = serializers.URLField()
class Meta:
model = ChildModelA
fields = [
"attributeC",
"attributeD",
]
class ChildModelBSerializer(ParentModelSerializer):
...
ParentModelSerializer.model_serializer_mapping = {
ChildModelA: ChildModelASerializer,
ChildModelB: ChildModelBSerializer
...
}
- Stacktrace when attempting to access any ParentModel or ChildModel resource using DRF:
Stacktrace
Internal Server Error: /api/v1/parentmodel/33fe48b6-eb67-40e0-8910-cafce5b61ea5/
Traceback (most recent call last):
File "/home/dev/Devel/project/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
response = get_response(request)
File "/home/dev/Devel/project/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/django/views/decorators/csrf.py", line 54, in wrapped_view
return view_func(*args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/django/views/generic/base.py", line 70, in view
return self.dispatch(request, *args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/views.py", line 509, in dispatch
response = self.handle_exception(exc)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/views.py", line 469, in handle_exception
self.raise_uncaught_exception(exc)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/views.py", line 480, in raise_uncaught_exception
raise exc
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/views.py", line 506, in dispatch
response = handler(request, *args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/generics.py", line 208, in get
return self.retrieve(request, *args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/mixins.py", line 55, in retrieve
serializer = self.get_serializer(instance)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_framework/generics.py", line 110, in get_serializer
return serializer_class(*args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_polymorphic/serializers.py", line 40, in __init__
serializer = serializer(*args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_polymorphic/serializers.py", line 40, in __init__
serializer = serializer(*args, **kwargs)
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_polymorphic/serializers.py", line 40, in __init__
serializer = serializer(*args, **kwargs)
[Previous line repeated 472 more times]
File "/home/dev/Devel/project/lib/python3.9/site-packages/rest_polymorphic/serializers.py", line 22, in __new__
if not isinstance(cls.resource_type_field_name, string_types):
RecursionError: maximum recursion depth exceeded in __instancecheck__
I came up with this workaround but I think we can all agree this looks kinda hacky...
In the serializers file:
class ParentModelSerializer(PolymorphicSerializer):
pass
class ParentModelSerializerFieldsMixin(serializers.ModelSerializer):
attributeA = serializers.CharField()
attributeB = serializers.IntField()
class Meta:
model = ParentModel
fields = [
"attributeA",
"attributeB",
]
class ChildModelASerializer(ParentModelSerializerFieldsMixin):
attributeC = serializers.HyperlinkedRelatedField()
attributeD = serializers.URLField()
class Meta:
model = ChildModelA
fields = [
"attributeC",
"attributeD",
]
class ChildModelBSerializer(ParentModelSerializerFieldsMixin):
...
ParentModelSerializer.model_serializer_mapping = {
ChildModelA: ChildModelASerializer,
ChildModelB: ChildModelBSerializer
...
}