Overriding to_representation() in Django REST Framework

Last updated 1 month, 1 week ago | 113 views 75     5

Tags:- Python Django DRF

In Django REST Framework (DRF), serializers convert model instances into JSON-friendly Python data types. Normally, this is handled automatically. But sometimes, you need more control over the final output — for example, to:

  • Add or remove fields conditionally

  • Modify nested data

  • Format values differently

For these situations, DRF allows you to override the to_representation() method.


What is to_representation()?

to_representation() is a method on a serializer class that defines how an object instance is converted to a native Python datatype suitable for rendering as JSON.

It is automatically called during serialization.

def to_representation(self, instance):
    # return dict representing instance

Basic Usage Example

Scenario: You want to customize the output format of a Book model.

models.py

class Book(models.Model):
    title = models.CharField(max_length=100)
    pages = models.IntegerField()
    published = models.BooleanField()

serializers.py

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['title', 'pages', 'published']

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['pages'] = f"{data['pages']} pages"
        data['status'] = 'Published' if instance.published else 'Unpublished'
        return data

Output

{
  "title": "Learn DRF",
  "pages": "250 pages",
  "published": true,
  "status": "Published"
}

You can see how we:

  • Added a new field (status)

  • Transformed the value of pages


✅ Use Cases for to_representation()

Use Case Description
Custom field formatting Change how data is displayed
Conditional field inclusion Show/hide fields based on logic
Nested representation tweaks Modify how nested serializers behave
Output simplification Flatten or restructure complex data

Conditional Fields Example

def to_representation(self, instance):
    data = super().to_representation(instance)
    request = self.context.get('request')

    if request and request.user.is_staff:
        data['internal_notes'] = instance.internal_notes
    return data

This will only include internal_notes for staff users.


Working with Nested Serializers

Suppose you want to show the author's full name from a related model.

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['title', 'author']

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['author'] = instance.author.get_full_name()
        return data

Full Working Example

models.py

class Author(models.Model):
    first_name = models.CharField(max_length=100)
    last_name = models.CharField(max_length=100)

    def full_name(self):
        return f"{self.first_name} {self.last_name}"

class Book(models.Model):
    title = models.CharField(max_length=100)
    author = models.ForeignKey(Author, on_delete=models.CASCADE)
    is_featured = models.BooleanField(default=False)

serializers.py

class BookSerializer(serializers.ModelSerializer):
    class Meta:
        model = Book
        fields = ['title', 'author', 'is_featured']

    def to_representation(self, instance):
        data = super().to_representation(instance)
        data['author'] = instance.author.full_name()
        if not instance.is_featured:
            data.pop('is_featured')
        return data

Output

{
  "title": "DRF Advanced",
  "author": "Jane Doe"
}

⚠️ Common Pitfalls

Pitfall Fix
❌ Forgetting super() call Always start with super().to_representation(instance)
❌ Incorrect context handling Use self.context.get('request') safely
❌ Overcomplicating logic Consider using SerializerMethodField for single fields
❌ Inconsistent output format Ensure all expected fields are returned, even if empty

✅ Best Practices

  • ✅ Use to_representation() for whole-object transformations

  • ✅ Use SerializerMethodField for field-level customization

  • ✅ Minimize logic inside serializers — offload to models or services when possible

  • ✅ Always return a dictionary from to_representation()


When to Avoid Overriding to_representation()

Situation Better Alternative
Need to customize just one field Use SerializerMethodField
Need write support Use create() / update() methods
Business logic is complex Move to service layer or model method

✅ Summary

Feature Description
to_representation() Customizes how instances are turned into JSON
Return type Python dict
Use cases Conditional fields, nested data, formatting
When called During serialization (not deserialization)
Key tip Call super() first to retain default behavior

Conclusion

Overriding to_representation() is a powerful way to customize the JSON output of your serializers in DRF. It gives you full control over what data is returned, how it is formatted, and when it appears.

Use it wisely to build flexible, user-friendly, and performant APIs.