Skip to content

Instantly share code, notes, and snippets.

@salomvary
Created March 7, 2025 16:06
Show Gist options
  • Save salomvary/b8c49ab456dff7d12812542934a85150 to your computer and use it in GitHub Desktop.
Save salomvary/b8c49ab456dff7d12812542934a85150 to your computer and use it in GitHub Desktop.
Efficient Django Rest Framework (DRF) Serializers
#
# How to write performant serializers for Django REST Framework.
#
# Focusing on serialization, but mostly also applicable to deserialization.
# Remember: do not optimize prematurely, always measure performance first.
# But if you are planning to serialize large and complicated data structures,
# it is very likely that you will not want to use ModelSerializers.
from functools import lru_cache
from django.db import models
from rest_framework import serializers
class SomeModel(models.Model):
field1 = models.CharField()
field2 = models.CharField()
# Do NOT use ModelSerializers for non-trivial serialization.
# They are inherently slow. Acceptable for a dozen of fields,
# or lists of a dozen elements.
class SomeModelSerializer(serializers.ModelSerializer):
class Meta:
model = SomeModel
fields = ["field1", "field2"]
# Serialize with it like this:
SomeModelSerializer().to_representation(SomeModel.objects.first())
SomeModelSerializer(many=True).to_representation(SomeModel.objects.all())
# DO use plain serializers.
# They are faster, and the code-overhead of explicitly defining
# fields is not huge.
class SomePlainSerializer(serializers.Serializer):
field1 = serializers.CharField()
field2 = serializers.CharField()
# Same serialization patterns work here:
SomePlainSerializer().to_representation(SomeModel.objects.first())
SomePlainSerializer(many=True).to_representation(SomeModel.objects.all())
# Also note that serializer instances can be reused:
serializer = SomePlainSerializer()
serializer.to_representation(SomeModel.objects.first())
serializer.to_representation(SomeModel.objects.last())
class ChildSerializer(serializers.Serializer):
field2 = serializers.CharField()
# DO use child serializers as a serializer field
class ParentSerializer(serializers.Serializer):
field1 = serializers.CharField()
child_field = ChildSerializer(source="field2")
# You can also pass the entire parent instance to the child serializer
class ParentSerializer(serializers.Serializer):
field1 = serializers.CharField()
child_field = ChildSerializer(source="*")
# Do NOT instantiate serializers from a SerializerMethodField
class ParentSerializer(serializers.Serializer):
field1 = serializers.CharField()
child_field = serializers.SerializerMethodField()
def get_child_field(self, instance):
# Instantiating serializers is expensive, and if ParentSerializer is used
# in a list, the performance impact will be significant.
return ChildSerializer(context=self.context).to_representation(instance.field2)
# If SerializerMethodField is unavoidable,
# DO cache the child serializer on the parent serializer
class ParentSerializer(serializers.Serializer):
field1 = serializers.CharField()
child_field = serializers.SerializerMethodField()
def get_child_field(self, instance):
# Instantiating serializers is expensive, and if ParentSerializer is used
# in a list, the performance impact will be significant.
return self._get_child_serializer().to_representation(instance.field2)
@lru_cache
def _get_child_serializer(self):
# Assuming that ParentSerializer does not modify the context.
return ChildSerializer(context=self.context)
# Bonus: DO consider not passing in models to serializers at all.
# This saves the cost of instantiating a model instance, which might
# or might not matter for your use case.
# Also beware that nested relations selected with .values("parent__child")
# will not be exposed as nested objects but as flat fields, which requires
# writing serializers differently, or preprocessing the return value
# from the queryset before passing it to the serializer.
SomePlainSerializer().to_representation(
SomeModel.objects.values("field1", "field2").first()
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment