James Maguire
James Maguire

Reputation: 570

Logic on serializer fields

I am trying to work out how to run some logic to get certain objects from within my serializer (or elsewhere).

I have the following:

class Parent(models.Model):
    name = models.CharField(max_length=255)


class Child(models.Model):
    name = models.CharField(max_length=255)
    parent = models.ForeignKey(
        Parent, related_name='children', on_delete=models.CASCADE)


class ChildSerializer(serializers.ModelSerializer):
    class Meta:
        model = Child
        fields = (
            'id',
            'name',
        )


class ParentSerializer(serializers.ModelSerializer):
    children = ChildSerializer()

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


class ParentViewSet(viewsets.ModelViewSet):
    serializer_class = ParentSerializer
    queryset = Parent.objects.all()


class ChildViewSet(viewsets.ModelViewSet):
    serializer_class = ChildSerializer
    queryset = Child.objects.all()

I would like to add a field to the parent response: first_child which is the first child alphabetically by name (this logic would be slightly more complex in reality, the largest value of the sum of multiple fields for example). I will also remove the children field in favor of this first_child field as the number of those will be too high to display in-line like this.

Upvotes: 0

Views: 59

Answers (1)

Zkh
Zkh

Reputation: 593

You can use to_representation method

class ParentSerializer(serializers.ModelSerializer):
    children = ChildSerializer()

    def to_representation(self, instance):
        data = super().to_representation(instance=instance)
        first_child = instance.children.order_by("name").first()
        data["first_child"] = ChildSerializer(first_child, read_only=True).data if first_child else None
        return data

    class Meta:
        model = Parent # change model name
        fields = (
            'id',
            'name',
            'children',
        )

Or, use SerializerMethodField:

class ParentSerializer(serializers.ModelSerializer):
    children = ChildSerializer()
    first_child = serializers.SerializerMethodField()

    def get_first_child(self, instance):
        first_child = instance.children.order_by("name").first()
        if first_child:
             return ChildSerializer(first_child, read_only=True).data
        return None

    class Meta:
        model = Parent # Change model here
        fields = (
            'id',
            'name',
            'children',
            'first_child',
        )

Upvotes: 1

Related Questions