Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django rest framework represent flatten nested object

I have a parent and a one-to-one related child model and I would like to render the fields from the child flat in the parent representation (read only). Currently, I have achieved that with a custom to_representation implementation but that seems very involved and I wonder if there is no easier way to achieve this.

It is made more complicated by the fact that my related model is connected via a property.

So here is the concrete example: By default a related object would be rendered like:

{
  parent_name:'Bob', 
  child:{
    name:'Alice'
  }
}

This is what I want and currently get with my to_representation:

{
  parent_name:'Bob',       
  child_name:'Alice'
}

My models look like this:

class ChildModel(models.Model):
    name = models.CharField(max_length=100, null=True)

class ParentModel(models.Model):
    name = models.CharField(max_length=100, null=True)
    _child = models.ForeignKey('ChildModel', null=True)

    @property
    def child(self):
        return self._most_recent_status

    @name.setter
    def child(self, value):
        self._child = value

Here are my serializers:

class FlatChildField(serializers.RelatedField):
    def to_representation(self, value):
        return value.name


class FlatParentSerializer(serializers.ModelSerializer):    
    parent_name = serializers.CharField(source='name', read_only=True)
    child_name = FlatChildField(source='_child', read_only=True)

    class Meta:
         model = Parent
         fields = ('name', 'child_name')

For a simpler solution to get a flat representation of related models I would be grateful.

For completeness, I would be interested to hear if there is a simpler solution for "normal" related models (i.e. not property model fields as well). I was looking for the equivalent of the django model query syntax of related_model__field, but I cannot find that. Does that exist for django rest framework?

Many thanks

like image 801
Dan Schien Avatar asked Dec 15 '15 10:12

Dan Schien


2 Answers

The simplest means would be to use source:

class FlatParentSerializer(serializers.ModelSerializer):    
    parent_name = serializers.CharField(source='name', read_only=True)
    child_name =  serializers.CharField(source='_child.name', read_only=True)

    class Meta:
        model = Parent
        fields = ('name', 'child_name')
like image 171
Rex Salisbury Avatar answered Sep 20 '22 15:09

Rex Salisbury


You can use SerializerMethodField, it saves you really a lot of work and it's so clean and trivial:

class FlatParentSerializer(serializers.ModelSerializer):    
    parent_name = serializers.CharField(source='name', read_only=True)
    child_name =  serializers.SerializerMethodField('get_child_name')

    class Meta:
         model = Parent
         fields = ('name', 'child_name')

    def get_child_name(self, obj):
        return obj._child.name
like image 37
Dhia Avatar answered Sep 22 '22 15:09

Dhia