I can't find this info in the docs or on the interwebs.
 latest django-rest-framework, django 1.6.5  
How does one create a ModelSerializer that can handle a nested serializers where the nested model is implemented using multitable inheritance?
e.g.
######## MODELS class OtherModel(models.Model):     stuff = models.CharField(max_length=255)  class MyBaseModel(models.Model):     whaddup = models.CharField(max_length=255)     other_model = models.ForeignKey(OtherModel)  class ModelA(MyBaseModel):     attr_a = models.CharField(max_length=255)  class ModelB(MyBaseModel):     attr_b = models.CharField(max_length=255)   ####### SERIALIZERS class MyBaseModelSerializer(serializers.ModelSerializer):     class Meta:         model=MyBaseModel  class OtherModelSerializer(serializer.ModelSerializer):     mybasemodel_set = MyBaseModelSerializer(many=True)      class Meta:         model = OtherModel   This obviously doesn't work but illustrates what i'm trying to do here.
 In OtherModelSerializer, I'd like mybasemodel_set to serialize specific represenntations of either ModelA or ModelB depending on what we have.
If it matters, I'm also using django.model_utils and inheritencemanager so i can retrieve a queryset where each instance is already an instance of appropriate subclass.
Thanks
Serializers in Django REST Framework are responsible for converting objects into data types understandable by javascript and front-end frameworks. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.
DRF provides a Serializer class that gives you a powerful, generic way to control the output of your responses, as well as a ModelSerializer class that provides a useful shortcut for creating serializers that deal with model instances and querysets.
ModelSerializer is a layer of abstraction over the default serializer that allows to quickly create a serializer for a model in Django. Django REST Framework is a wrapper over default Django Framework, basically used to create APIs of various kinds.
I've solved this issue a slightly different way.
Using:
My models.py look like this:
class Person(models.Model):     first_name = models.CharField(max_length=40, blank=False, null=False)     middle_name = models.CharField(max_length=80, blank=True, null=True)     last_name = models.CharField(max_length=80, blank=False, null=False)     family = models.ForeignKey(Family, blank=True, null=True)   class Clergy(Person):     category = models.IntegerField(choices=CATEGORY, blank=True, null=True)     external = models.NullBooleanField(default=False, null=True)     clergy_status = models.ForeignKey(ClergyStatus, related_name="%(class)s_status", blank=True, null=True)   class Religious(Person):     religious_order = models.ForeignKey(ReligiousOrder, blank=True, null=True)     major_superior = models.ForeignKey(Person, blank=True, null=True, related_name="%(class)s_superior")   class ReligiousOrder(models.Model):     name = models.CharField(max_length=255, blank=False, null=False)     initials = models.CharField(max_length=20, blank=False, null=False)   class ClergyStatus(models.Model):     display_name = models.CharField(max_length=255, blank=True, null=True)     description = models.CharField(max_length=255, blank=True, null=True)   Basically - The base model is the "Person" model - and a person can either be Clergy, Religious, or neither and simply be a "Person".  While the models that inherit Person have special relationships as well.
In my views.py I utilize a mixin to "inject" the subclasses into the queryset like so:
class PersonSubClassFieldsMixin(object):      def get_queryset(self):         return Person.objects.select_subclasses()  class RetrievePersonAPIView(PersonSubClassFieldsMixin, generics.RetrieveDestroyAPIView):     serializer_class = PersonListSerializer     ...   And then real "unDRY" part comes in serializers.py where I declare the "base" PersonListSerializer, but override the to_representation method to return special serailzers based on the instance type like so:
class PersonListSerializer(serializers.ModelSerializer):      def to_representation(self, instance):         if isinstance(instance, Clergy):             return ClergySerializer(instance=instance).data         elif isinstance(instance, Religious):             return ReligiousSerializer(instance=instance).data         else:             return LaySerializer(instance=instance).data      class Meta:         model = Person         fields = '__all__'   class ReligiousSerializer(serializers.ModelSerializer):     class Meta:         model = Religious         fields = '__all__'         depth = 2   class LaySerializer(serializers.ModelSerializer):     class Meta:         model = Person         fields = '__all__'   class ClergySerializer(serializers.ModelSerializer):     class Meta:         model = Clergy         fields = '__all__'         depth = 2   The "switch" happens in the to_representation method of the main serializer (PersonListSerializer).  It looks at the instance type, and then "injects" the needed serializer.  Since Clergy, Religious are all inherited from Person getting back a Person that is also a Clergy member, returns all the Person fields and all the Clergy fields.  Same goes for Religious.  And if the Person is neither Clergy or Religious - the base model fields are only returned.
Not sure if this is the proper approach - but it seems very flexible, and fits my usecase.  Note that I save/update/create Person thru different views/serializers - so I don't have to worry about that with this type of setup.
I was able to do this by creating a custom relatedfield
class MyBaseModelField(serializers.RelatedField):     def to_native(self, value):         if isinstance(value, ModelA):             a_s = ModelASerializer(instance=value)             return a_s.data         if isinstance(value, ModelB):             b_s = ModelBSerializer(instance=value)             return b_s.data          raise NotImplementedError   class OtherModelSerializer(serializer.ModelSerializer):     mybasemodel_set = MyBaseModelField(many=True)      class Meta:         model = OtherModel         fields = # make sure we manually include the reverse relation (mybasemodel_set, )   I do have concerns that instanting a Serializer for each object is the reverse relation queryset is expensive so I'm wondering if there is a better way to do this.
Another approach i tried was dynamically changing the model field on MyBaseModelSerializer inside of __init__ but I ran into the issue described here:
django rest framework nested modelserializer
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With