Dan Russell
Dan Russell

Reputation: 970

Django REST Framework: Serializing through multiple relationships

In Django, I have the following models.

class Genus(models.Model):
    genus_name=models.CharField(max_length=30)
    ...

class HostSpecies(models.Model):
    species_genus=models.ForeignKey(Genus)
    ...

class HostStrain(models.Model):
    strain_species=models.ForeignKey(HostSpecies)
    strain_name=models.CharField(max_length=50)
    ...

Now I'm trying to use Django REST Framework to serialize the the HostStrain model as follows.

class HostStrainSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = HostStrain
        fields = ('strain_species__species_genus','strain_species','strain_name')

But the standard double-underscore notation in Django doesn't seem to work here, since I get the error:

Field name strain_species__species_genus is not valid for model HostStrain.

I'd like to include a link to (or at least the __unicode__ from) the Genus model in my HostStrain serialization.

So how do I follow multi-level relationships in Django REST Framework's serialization?

Upvotes: 1

Views: 904

Answers (1)

Eduardo Cardoso
Eduardo Cardoso

Reputation: 196

There are a few ways you can do this.

You can include other serializers on your HostStrainSerializer

class GenusSerializer(serializers.HyperlinkedModelSerializer):
    class Meta:
        model = Genus
        fields = ('genus_name')

class HostSpeciesSerializer(serializers.HyperlinkedModelSerializer):
    species_genus = GenusSerializer()

    class Meta:
        model = HostSpecies
        fields = ('species_genus')

class HostStrainSerializer(serializers.HyperlinkedModelSerializer):
    strain_species = HostSpeciesSerializer()

    class Meta:
        model = HostStrain
        fields = ('strain_species','strain_name')

This way your serializer will output something like this:

{
    "strain_name": "...",
    "strain_species": {
        "species_genus": {
            "genus_name": "..."
        }
    }
}

Another way you can do this is to create fields on your HostStrainSerializer that gets the information from the other models.

class HostStrainSerializer(serializers.HyperlinkedModelSerializer):
    strain_species = HostSpeciesSerializer()
    species_genus = serializers.ReadOnlyField(source='strain_species.species_genus.genus_name')

    class Meta:
        model = HostStrain
        fields = ('species_genus', 'strain_species','strain_name')

You can also use a SerializerMethodField

class HostStrainSerializer(serializers.HyperlinkedModelSerializer):
    strain_species = HostSpeciesSerializer()
    species_genus = serializers.SerializerMethodField()

    def get_species_genus(self, instance):
        return instance.strain_species.species_genus.genus_name

    class Meta:
        model = HostStrain
        fields = ('species_genus', 'strain_species','strain_name')

Upvotes: 2

Related Questions