Understanding DRF’s Serializer
Introduction
This post explains the basic features of django DRF’s serializer.
Serializer?
- Serializer is a handy tool / component built in the Django Rest Framework, that helps you convert complex data such as querysets and model instances into python datatypes that can then be turned into JSON or other content types. It also allows you to convert the parsed data back into complex types, after validating the data
Getting Started
Why do we need it?
Suppose that you have a UserProfile model looking like this
class UserProfile(models.Model):
uid = models.UUIDField(primary_key=True, default=uuid.uuid4,
editable=False, unique=True)
user = models.ForeignKey(User, on_delete=models.CASCADE,
related_name='profiles')
profile_name = models.CharField(null=True, max_length=30)
bio_title = models.CharField(null=True, max_length=40)
bio = models.CharField(null=True, max_length=155)
job_title = models.CharField(null=True, max_length=40)
job_description = models.CharField(null=True, max_length=155)
# and perhaps some more fields
Now imagine creating an instance of that in views.py using the data from the request. It would look something like this
# ASSUMING YOU ALREADY HAVE A 'user' object
post_data = request.data
try:
profile_name = post_data['profile_name']
bio_title = post_data['bio_title']
bio = post_data['bio']
job_title = post_data['job_title']
job_description = post_data['job_description']
except KeyError:
# handling error in case the post data doesn't contain certain values
# manually creating an instance
instance = UserProfile(user=user, email=email,
profile_name=profile_name
...
)
instance.save()
This already looks repetitive, and an error can easily occur. This is NOT what we want. Which is exactlly what serializers are for.
With serializer, the code would looke like this. The serializer would help convert the python’s datatypes into a complex model instance.
# with serializer
instance = UserProfileSerializer(data=request.data)
if instance.is_valid():
instance.save(user=user)
Setting Up
- Create a
serializers.pyfile inside your app directory, not the project directory. e.x:myproject/myapp/. - Create a serializer component. The following is an example serialzer for the UserProfile model above.
# import the necessary modules from rest_framework import serializers from .models import UserProfile class UserProfileSerializer(serializers.ModelSerializer): # you can set certain fields as read only as well uid = serializers.UUIDField(read_only=True) name = serializers.SerializerMethodField(read_only=True) gender = serializers.SerializerMethodField(read_only=True) age = serializers.SerializerMethodField(read_only=True) # defining the fields that the serializer is going to include class Meta: model = UserProfile # define the depth of relationships depth = 1 fields = [ "uid", "profile_name", "bio_title", "bio", "job_title", "job_description", # You can even get data from the User instance that # the serializer is linked to "name", "gender", "age", ] def get_name(self, obj): # the serializer would traverse the relationship # to query these data return obj.user.name def get_age(self, obj): return obj.user.age def get_gender(self, obj): return obj.user.genderdepth- The depth option should be set to an integer value that indicates the depth of relationships that should be traversed before reverting to a flat representation(from official doc)
fields- a list of strings that indicates which fields is included in this serializer
get_{field name}functions- some data’s cannot be directly queried, or you may want to customize the values of some fields.
- that is when you use the functions starting with
get. So for example, theget_namefunction in the code above reads thenamefield from the user instance that is set as foreign key to the UserProfile model, and allow us to easily access it via serialzer
How to use
Turning Complex Data -> Python Datatype
Let’s say that you want to return the user’s profile data as a response. You can use the serializer to turn the instance of an model into a dictionary, then return it using Response.
profile = UserProfile.objects.get(uid=uid)
serializer = UserProfileSerializer(profile)
return Response(serializer.data)
It’s that easy. It automatically converts the model instance into a dictionary, then you return that dictionary using Response whcih will returned the data in json format. Like below
{
"uid": "9e168432-6522-4461-aa1f-39251d7daeb5",
"profile_name": "asdf",
"name": "asdf",
"gender": "asdf",
"age": 100,
...
...
}
Turning Python Datatype -> Complex Data
Now let’s turn python datatype into complex datatypes, in many cases, serializer instance itself. I explained it earlier in this post. But let’s look at it in more detail.
instance = UserProfileSerializer(data=request.data)
if instance.is_valid():
instance.save(user=user)
In this case, the request.data instance is not a built-in python datatype like dictionary. However, you can turn a dictionary into a model instance in the exact same way.
data = {
"profile_name": "asdf",
"bio": "asdf"
...
...
}
serializer = UserProfileSerializer(data=data)
if serializer.is_valid():
user_profile = serializer.save()
Other Uses
You can also use serializer for other uses, like updating an instance.
# querying the outdated profile
profile = UserProfile.objects.get(uid=uid)
serializer = UserProfileSerializer(profile, data=request.data)
if serializer.is_valid():
# changing the old data with the new data
serializer.update(instance=profile, validated_data=request.data)