Overriding to_representation() in Django REST Framework
Last updated 1 month, 1 week ago | 113 views 75 5

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.