44
loading...
This website collects cookies to deliver better user experience
serializers
and decided that it's that time of the year again where I start thinking that I should have a blog where I can save my notes -then forget about it again-, but as I already got a blog I said why not 🤔 ? ... let's create a digital copy of my drf serializer notes, maybe someone will find it useful.save time creating django apis with this cool django package, and support the repository by dropping a star ⭐
1 - Fields
--------------------------
- Serializer Method Field
- Read Only Field
- Custom Field Validation
- Using Multiple Serializers
--------------------------
2 - Data
--------------------------
- Custom Data Validation
- Custom Output with `to_representation`()
- Custom Input with `to_internal_value`().
- Pass additional data directly to `save()`
--------------------------
3 - Keywords
--------------------------
- The `source` Keyword
- The `context` Keyword
SerializerMethodField
gets its data by calling get_<field_name>
.class UserSerializer(serializers.ModelSerializer):
days_since_joined = serializers.SerializerMethodField()
class Meta:
model = User
fields = '__all__'
def get_days_since_joined(self, obj):
return (now() - obj.date_joined).days
read_only
fields that are incorrectly included in the serializer input will be ignored.class AccountSerializer(serializers.Serializer):
id = IntegerField(label='ID', read_only=True)
class StudentSerializer(serializers.ModelSerializer):
...
def validate_age(self, age):
if age > 18 or age < 12:
raise serializers.ValidationError('Age has to be between 12 and 18.')
return age
get_serializer_class()
of your ViewSet
when for example you want to use a different Serializer in your create and update actions like the following:class MyViewSet(viewsets.ModelViewSet):
queryset = MyModel.objects.all()
def get_serializer_class(self):
if self.action in ["create", "update"]:
return WriteSerializer
return ReadSerializer
class OrderSerializer(serializers.ModelSerializer):
...
def validate(self, data):
if data['discount_amount'] > data['total_amount']:
raise serializers.ValidationError('discount cannot be bigger than the total amount')
return data
def is_valid_age(value):
if age < 12:
raise serializers.ValidationError('age cannot be lower than 12.')
elif age > 18:
raise serializers.ValidationError('age cannot be higher than 18')
class AnotherSerializer(serializers.ModelSerializer):
age = IntegerField(validators=[is_valid_age])
to_representation()
, imagine you have an output like the following after serialization is completed:{
"id": 1,
"username": "abdenasser",
"bio": "Hey ... you already know!",
"followed_by": [2, 3]
}
class ResourceSerializer(serializers.ModelSerializer):
...
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['followers'] = instance.followed_by.count()
return representation
{
"id": 1,
"username": "abdenasser",
"bio": "Hey ... you already know!",
"followed_by": [2, 3],
"followers": 2
}
to_internal_value()
as follow:class SomeSerializer(serializers.ModelSerializer):
...
def to_internal_value(self, data):
useful_data = data['useful']
return super().to_internal_value(useful_data)
.save()
will either create a new instance, or update an existing instance, depending on if an existing instance was passed when instantiating the serializer class:# .save() will create a new instance.
serializer = CommentSerializer(data=data)
# .save() will update the existing `comment` instance.
serializer = CommentSerializer(comment, data=data)
source
in a field like thisfield_name = serializers.SomeFieldType(source='prop')
prop
could be a call for a function that return some value, or a property that exists in a related model like ...(source='author.bio')
or even a serializer field that you want to rename in output.source='*'
if you need.resource = Resource.objects.get(id=1)
serializer = ResourceSerializer(resource, context={'key': 'value'})
def to_representation(self, instance):
representation = super().to_representation(instance)
representation['key'] = self.context['key']
return representation