Praful Bagai
Praful Bagai

Reputation: 17382

Django DRF - What's the use of serializers?

I've been using Django for over 3 years now, but have never felt the need to use DRF. However, seeing the growing popularity of DRF, I thought of giving it a try.

Serializing is the concept I find it most difficult. Consider for eg:- I want to save user details. Following is the user related models.

class Users(models.Model):
    GENDER_CHOICES = (
        ('M', 'MALE'),
        ('F', 'FEMALE'),
        ('O', 'OTHERS'),
    )
    first_name = models.CharField(max_length=255, blank=True, null=True)
    middle_name = models.CharField(max_length=255, blank=True, null=True)
    last_name = models.CharField(max_length=255, blank=True, null=True)
    gender = models.CharField(choices=GENDER_CHOICES, max_length=1, blank=True,
                              null=True)


class UserAddress(models.Model):
    ADDRESS_TYPE_CHOICES = (
        ('P', 'Permanent'),
        ('Cu', 'Current'),
        ('Co', 'Correspondence')
    )
    line1 = models.CharField(max_length=255)
    line2 = models.CharField(max_length=255, blank=True, null=True)
    pincode = models.IntegerField()
    address_type = models.CharField(choices=ADDRESS_TYPE_CHOICES,
                                    max_length=255)
    user_id = models.ForeignKey(Users, related_name='uaddress')


class UserPhone(models.Model):
    phone = models.CharField(max_length=10)
    user_id = models.ForeignKey(Users, related_name='uphone')


class UserPastProfession(models.Model):
    profession = models.CharField(max_length=10)  # BusinessMan, software Engineer, Artist etc.
    user_id = models.ForeignKey(Users, related_name='uprofession')

I'm getting all the user details bundled in one POST endpoint.

{
    'first_name': 'first_name',
    'middle_name': 'middle_name',
    'last_name': 'last_name',
    'gender': 'gender',
    'address': [{
        'line1': 'line1',
        'line2': 'line2',
        'address_type': 'address_type',
    }],
    'phone': ['phone1', 'phone2'],
    'profession': ['BusinessMan', 'Software Engineer', 'Artist']
}

Without using DRF, I would have made a Users object first, linking it with UserAddress, UserPhone and UserPastProfession object.

How the same could be done using DRF? I mean validating, serializing, and then saving the details. How serializers.py file will be look like?

Upvotes: 10

Views: 7888

Answers (3)

Syed Faizan
Syed Faizan

Reputation: 1056

If you want to make your life easy, you will surely use it.

Serializers allow complex data such as querysets and model instances to be converted to native Python datatypes that can then be easily rendered into JSON, XML or other content types. Serializers also provide deserialization, allowing parsed data to be converted back into complex types, after first validating the incoming data.

This gives you a generic way to control the output of your responses, as well as a ModelSerializer class which provides a useful shortcut for creating serializers that deal with model instances and querysets.

They save you from writing a lot of custom code. Let’s look at some examples.

Pretend we have an app that tracks a list of tasks that the user has to complete by a certain date. The Task model might look something like the following:

class Task(models.Model):
    title = models.CharField(max_length=255)
    due_date = models.DateField() 
    completed = models.BooleanField(default=False)

When the user requests those tasks, our app returns a response in the form of a JSON-serialized string. What happens when we try to serialize our Django objects using the built-in json library?

import json
task = Task.objects.first()
json.dumps(task)

We get a TypeError. Task is not JSON serializable. To bypass this, we have to explicitly create a dictionary with each of the attributes from Task.

json.dumps({
    'title': task.title,
    'due_date': task.due_date.strftime('%Y-%m-%d'),
    'completed': task.completed
}) 

Serializing a Python object from a JSON string or from request data is just as painful.

from datetime import datetime 
title = request.data.get('title')
due_date = datetime.strptime(request.data.get('due_date'), '%Y-%m-%d').date()
completed = request.data.get('completed')
task = Task.objects.create(title=title, due_date=due_date, completed=completed) 

Now, imagine having to follow these steps in multiple views if you have more than one API that needs to serialize (or deserialize) JSON data. Also, if your Django model changes, you have to track down and edit all of the custom serialization code.

Creating and using a serializer is easy:

from rest_framework import serializers 
class TaskSerializer(serializers.ModelSerializer):
    def create(self, validated_data):
        return Task.objects.create(**validated_data)

    class Meta:
        model = Task
        fields = ('title', 'due_date', 'completed')

# Serialize Python object to JSON string. 
task_data = TaskSerializer(task).data 

# Create Python object from JSON string.
task_data = TaskSerializer(request.data)
task = task_data.create() 

If you update the Django model, you only have to update the serializer in one place and all of the code that depends on it works. You also get a lot of other goodies including (as you mentioned) data validation.

Hope that helps!

Upvotes: 23

Sabyasachi
Sabyasachi

Reputation: 1554

below is how your serializer can look.. but please go through this DRF serializer realtionship

from rest_framework.serializers import (
    ModelSerializer,
    PrimaryKeyRelatedField
)

class UserSerializer(ModelSerializer):
    """
    Serializer for the users models.. Please dont forget to import the model
    """
    class Meta:
        model = Users
        field = "__all__"


class UserPhoneSerializer(ModelSerializer):
    """
    Serializer for the users address model..
    Pass the previously created user id within the post.. serializer will automatically validate
    it
    """

    user_id = PrimaryKeyRelatedField(queryset=Users.objects.all())
    class Meta:
        model = UserPhone
        field = "__all__"

class UserAddressSerializer(ModelSerializer):
    """
    Serializer for the users address model..
    Pass the previously created user id within the post.. serializer will automatically validate
    it
    """

    user_id = PrimaryKeyRelatedField(queryset=Users.objects.all())
    class Meta:
        model = UserAddress
        field = "__all__"


class UserPastProfessionSerializer(ModelSerializer):
    """
    Serializer for the UserPastProfession model..
    Pass the previously created user id within the post.. serializer will automatically validate
    it
    """
    user_id = PrimaryKeyRelatedField(queryset=Users.objects.all())

    class Meta:
        model = UserPastProfession
        field = "__all__"

Upvotes: 0

Alihaydar Gubatov
Alihaydar Gubatov

Reputation: 1045

If I got you correctly, my answer is:

It is not necessary to write one serializer for a model, even for method type (POST,GET etc.). You can pretty much create serializers for your model as much as you need and set fields you want to operate on. You can also set those different serializers as serializer_class property of your APIView class per each method.

I strongly recommend you to take some time to look at the Django Rest Framework Tutorial

Upvotes: 3

Related Questions