• Jobs
  • About Us
  • professionals
    • Home
    • Jobs
    • Courses and challenges
  • business
    • Home
    • Post vacancy
    • Our process
    • Pricing
    • Assessments
    • Payroll
    • Blog
    • Sales
    • Salary Calculator

0

154
Views
Accessing particular instances in a DRF ListSerializer

I currently have this Django models I want to serialize:

class Result(models.Model):
    ...
    routes = models.ManyToManyField(Route)
    ...

class Route(models.Model):
    ...

class Feature(models.Model):
    result = models.ForeignKey(Result)
    route = models.ForeignKey(Route)
    description = models.TextField()

And the DRF serializers looks like:

class ResultSerializer(serializers.ModelSerializer):
    ...
    route = RouteSerializer(many=True, required=False)
    ...

    class Meta:
        model = Result
        fields = '__all__'

class FeatureField(serializers.CharField):
    """
    Accepts text in the writes and looks up the correct feature for the reads.
    """

    def get_attribute(self, obj):
        # We pass the object instance onto `to_representation`, not just the field attribute.
        return obj

    def to_representation(self, obj):
        try:
            search_result = self.root.child.instance
            # FIXME: this is the problem.
            feature = Feature.objects.get(route=obj.id, search_result=search_result)
            feature = feature.description
        except Feature.DoesNotExist:
            feature = None
        return feature


class RouteSerializer(serializers.ModelSerializer):
    description = FeatureField(required=False)

    class Meta:
        model = Route
        fields = '__all__'

The problem I mean in the code is that this works when I'm using a ResultSerializer with just one instance, but if I want to serialize several instances in a list view for example, and I pass a queryset to the serializer, DRF applies a ListSerializer on top of it and now the self.root.instance is a list of the records, and I can't access the individual Results that call the nested RouteSerializer so I can't retrieve the correct Feature.

about 3 years ago · Santiago Trujillo
1 answers
Answer question

0

I jumped into DRF code and finally understood what was going on:

If you serialize just one instance with serializer = ResultSerializer(result), the serializer.instance contains only this single, particular result instance, and the nested serializers and fields can access it without problem using self.root.instance.

Now, if you serialize several instances, like the default list action does, what really happens is the following:

  1. a call like serializer = ResultSerializer(queryset, many=True) is performed
  2. having many=True in the arguments triggers the many_init() method from BaseSerializer, and this creates a single ResultSerializer with the queryset as instance, so serializer.instance is the queryset.
  3. next it creates a single ListSerializer extending ResultSerializer and its instance again is the queryset.

What I got wrong is thinking that the ListSerializer would create separated ResultSerializers for each element in the queryset.

How I finally solved this is overriding the ResultSerializer.to_representation() method:

class ResultSerializer(serializers.ModelSerializer):
    def to_representation(self, instance):
        # When we call Results with many=True, the serializer.instance is a list with several records,
        # we can't know which particular instance is spawning the nested serializers so we add it here.
        self._instance = instance
        return super(ResultSerializer, self).to_representation(instance)

and finally consume it in the FeatureField like this:

class FeatureField(serializers.CharField):
    """
    Accepts text in the writes and looks up the correct feature for the reads.
    """

    def get_attribute(self, obj):
        # We pass the object instance onto `to_representation`, not just the field attribute.
        return obj

    def to_representation(self, obj):
        # If the root is a ListSerializer, retrieve the right Result instance using the `_instance` attribute.
        try:
            if isinstance(self.root, serializers.ListSerializer):
                search_result = self.root.child._instance
            else:
                search_result = self.root.instance
            feature = Feature.objects.get(route=obj.id, search_result=search_result)
            feature = feature.pickup_instructions
        except Feature.DoesNotExist:
            feature = None
        return feature
about 3 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Our process Sales
Legal
Terms and conditions Privacy policy
© 2025 PeakU Inc. All Rights Reserved.

Andres GPT

Recommend me some offers
I have an error