10

I have models - Commodity, Clother and child models, as Acessories, Outwear, etc.:

class Commodity(models.Model):
    atribute = models.CharField()

class Clother(models.Model):
    commodity = models.ForeignKey(Commodity)
    clother_atribute = models.CharField()

class Acessories(models.Model):
    clother = models.ForeignKey(Clother)
    acessories_atribute = models.CharField() 

class Outwear(models.Model):
    clother = models.ForeignKey(Clother)
    outwear_atribute = models.CharField()

How can I serialize the parent model Commodity to call all vertical dependencies? I suppose to query Commodity id and get all Clother attributes and Acessories or Outwear attributes.

Art
  • 2,836
  • 4
  • 17
  • 34
D. Make
  • 579
  • 2
  • 6
  • 23

4 Answers4

12

If I understood your problem you can define ClotherSerializer. You can use depth = 1 to serialize nested objects in this serializer:

class ClotherSerializer(serializers.ModelSerializer):
    class Meta:
        model = Clother
        fields = ('id', 'acessories_set', 'outwear_set')
        depth = 1

Later in your CommoditySerializer you can use ClotherSerializer to serialize clother and all it's relation:

class CommoditySerializer(serializers.ModelSerializer):
    clother_set = ClotherSerializer(many=True)
    class Meta:
        model = Commodity
        fields = ('id', 'clother_set')
neverwalkaloner
  • 46,181
  • 7
  • 92
  • 100
  • Can you actually passe a list of children in the parent's object, to create a parent and multiple children at the same time? Have tried but for some reason it seems that the parent object doesn't accept a list of children objects, although their relationship has been clearly defined in their models. Any hint on how to manage this? – Seb Oct 06 '20 at 10:09
  • @Seb try to check writable nested serializer part in the docs: https://www.django-rest-framework.org/api-guide/relations/#writable-nested-serializers – neverwalkaloner Oct 06 '20 at 12:02
  • Thanks for the reply. So have tried but am still getting an error "Invalid data. Expected a dictionary, but got list." in the parent's object field corresponding to its children. Any hint on why it behaves that way when I have a many to one relationship between the children and the parent? – Seb Oct 08 '20 at 02:04
  • 1
    You my friend saved me so much time. For whatever reason I could not figure out this simple `depth = 1` fix. Thank you!! :) – Emmet Arries Aug 17 '22 at 00:05
9

Alternatively, this can also be achieved using SerializerMethodField: http://www.django-rest-framework.org/api-guide/fields/#serializermethodfield

class ClotherSerializer(serializers.ModelSerializer):
    """
    Serializer for Clother data model.
    """
    acessories = serializers.SerializerMethodField()
    outwears = serializers.SerializerMethodField()

    class Meta:
        model = Clother
        fields = ('id', 'acessories', 'outwears')

    def get_acessories(self, clother):
        return AcessoriesSerializer(clother.acessories_set.all(), many=True).data

    def get_outwears(self, clother):
        return OutwearSerializer(clother.outwear_set.all(), many=True).data


class CommoditySerializer(serializers.ModelSerializer):
    """
    Serializer for Commodity data model.
    """
    clother = serializers.SerializerMethodField()

    class Meta:
        model = Commodity
        fields = ('id', 'clother')

    def get_clother(self, commodity):
        return ClotherSerializer(commodity.clother_set.all(), many=True).data
mrehan
  • 1,122
  • 9
  • 18
2

You can use the drf-writable-nested [GitHub] package for that and specify in a serializer how to serialize certain fields. By using another serializer, you thus specify that it it serialized by calling the serializer for these children:

class CommoditySerializer(WritableNestedModelSerializer):
    clother_set = ClotherSerializer(many=True)

    class Meta:
        model = Commodity
        fields = ("atribute", 'clother_set')


class ClotherSerializer(WritableNestedModelSerializer):

    class Meta:
        model = Clother
        fields = ("clother_atribute",)

Of course you can add more such relations, for example to specify Acessories for a Clother.

I advice you look at the GitHub page, and use this as a template for your own serializer.

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
0

To achieve this functionality natively without any extra methods, you need only get the Clother dependency to the Commodity using it's related name. In this case, since the related_name reference is not defined, use the default related name like so:

...
class ClotherSerializer(serializers.ModelSerializer):
    """
    Serializer for Clother data model.
    """
    acessories_set = AccesoriesSerializer(many=True, read_only=True)
    outwears_set = OutwearsSerializer(many=True,read_only=True)

    class Meta:
        model = Clother
        fields = ('id', 'acessories_set', 'outwears_set')


class CommoditySerializer(serializers.ModelSerializer):
    """
    Serializer for Commodity data model.
    """
    clother_set = ClotherSerializer(many=True, read_only=True)

    class Meta:
        model = Commodity
        fields = ('id', 'clother_set')

Newton Karanu
  • 408
  • 5
  • 26