Super detailed explanation of serializer in Django DRF framework

preface

Over the past few years, I have been struggling in the it industry. Along the way, many have summarized some high-frequency interviews in the python industry. I see most of the new blood in the industry, and I still have all kinds of difficult questions for the answers to all kinds of interview questions or collection

Therefore, I developed an interview dictionary myself, hoping to help everyone, and also hope that more Python newcomers can really join the industry, so that Python fire does not just stay in advertising.

Wechat applet search: Python interview dictionary

Or follow the original personal blog: https://lienze.tech

You can also focus on WeChat official account and send all kinds of interesting technical articles at random: Python programming learning.

Serializer

Normal serializer

Response cannot directly return ORM data, so we need to serialize it. We can manually convert it into a dictionary or JSON * * *, or use the serializer provided by DRF. We generally recommend that you use the serializer *, which is more professional, simpler and more uniform in format

If you often use to encapsulate data into * * * JSON * * *, the common code model is like this

data = models.objects.all()
json_ = {}
for d in data:
    json_['age'] = d.age
    json_['name'] = d.name
return Response(json_)

If there are too many fields, the workload will become more and more troublesome. Moreover, it is impossible to serialize field types such as time (DateTimeField and DateField) directly through * * * JSON * * *. You need to manually write * * JSON serializer, which is very troublesome. Therefore, DRF provides two more convenient serializers, ordinary serializer and model serializer

Writing method of ordinary serializer

from rest_framework import serializers

The ordinary serializer can convert the matched ORM data field into * * * JSON * * * data according to the given field, not only for a piece of data, but also for the result set corresponding to a * * QuerySet

For example, a curriculum has the following fields

class Course(models.Model):
    name = models.CharField(max_length=20, verbose_name='Course name')
    created = models.DateField(verbose_name='Course creation time')
    def __str__(self):
        return self.name

Test data can be added manually through the database
Then the ordinary serializer can be defined as follows, which can be supported according to the model class fields. It is very simple

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField(auto_now_add=True)

Ordinary serializers can be defined not only for database model classes, but also for non database model classes. However, when defining model classes here, they need to be mapped one by one according to the model class fields

Normal serializer serialization

Serialization is to put ORM data into the serializer for processing, and generate * * * JSON * * * data object. The data attribute of the serializer object is the processed JSON data object

  • Serialization of a single piece of data

The serialization of singleton data is very simple. You can directly pass in the query result through the parameter * * * instance * * * of the serializer class object

object = models.objects.get(pk=1)
ser_data = Serializer(instance=object)
ser.data # This is the JSON result of this data
  • Serialization of multiple pieces of data

If you use some ORM methods such as * * * filter * * * and all to obtain the QuerySet result set instead of a separate data object, you need to pass in the many=True parameter to represent: Wow ~ 😲, A lot of data

objects = models.objects.all()
ser_data = Serializer(instance=objects, many=True)
ser_data.data # This is the JSON result of this group of data

Normal serializer deserialization creation

The concept of deserialization is very simple, which is to change JSON and other data into ORM data objects, or even warehousing or modification**

DRF requires that the serializer must verify the data in order to obtain the successfully verified data or save it as a model class object

  1. During the operation, deserialization first needs to pass parameters through data
  2. Then call is_valid for verification. If the verification is successful, it returns True. Otherwise, it returns False**
    1. If the verification fails, you can also return an error value through the errors property of the result
    2. ***is_valid * after calling, the method will verify the field attribute (max_value=10) * *, user-defined verification, etc
  3. Call the * * * save * * * method on the verified object. This * * save method will trigger the * * * create * * * method in the serializer
    1. In ordinary serializers, the * * * create * * * method is not implemented by default and needs to be written manually according to the model class
data = {
    'name':"Zhang San",
    ...
}
ser = Serializer(data=data)
if ser.is_valid():
    ser.save() # When only the data parameter is passed, the save method will trigger the create method in the serializer

For example, you can do this now or in the previous exercise when you need to submit data to create an interface for the course

In order to ensure the successful warehousing of data, the default ordinary serializer does not have the warehousing function, and the * * * create * * * method needs to be written

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField()
    def create(self, validated_data):
        object = Course.objects.create(
            **validated_data
        )
        return object

After success, you can complete the data warehousing by submitting the data and writing the view as before. The serializer can directly process the data submitted by * * * request * * * * * * data * * *, and can eliminate other redundant fields in * * request.data, only the fields in the serializer

class CourseCreate(APIView):
    def post(self, request):
        ser = CourseSer(data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

Normal serializer deserialization update

Deserialization of verified data can not only create data, but also update data

  1. Update first requires an existing data, so you need to pass an existing ORM object through the * * instance parameter
  2. If a new value to be updated is required, the * * * data * * * parameter needs to be passed
  3. After that, you also need * * * is_ The valid * * * method is called to check whether the incoming data to be updated is legal
  4. Finally, * * * save * * * triggers the * * * update * * * method in the serializer

The default ordinary serializer does not have its own update method for data. Now you need to create a * * * update * * * method in the serializer

class CourseSer(serializers.Serializer):
    name = serializers.CharField(max_length=20)
    created = serializers.DateField()
    def update(self, instance, validated_data):
        # instance data to be updated, validated_data is new data
        instance.name = validated_data.get('name', instance.name)
        instance.type = validated_data.get('create', instance.type)
        instance.save()
        return instance

Then pass the ID of the data to be updated and the updated value through PUT to update a piece of data

class CourseUpdate(APIView):
    def put(self, request):
        id_ = request.data.get("id") # Gets the ID of the current update data
        try:
            course = Course.objects.get(pk=id_)
        except Course.DoesNotExist:
            return Response({'msg': 'Update failed,This data does not exist'})
        ser = CourseSer(instance=course, data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

Model serializer

Model serializer writing method

In the previous serializer, it is obvious that if there are fewer model class fields, it is OK, but there are more and more model fields, the developers need to reproduce more and more fields in the serializer, which is very troublesome

In addition, you have to manually implement * * * update * * * and * * create methods, and you can't just write serializer fields. You also have to have field properties

Therefore, with the current serializer associated with the model class, it is more convenient to map fields and write built-in methods. It is great 👍

The model class association serializer has the following three characteristics and one disadvantage

  • characteristic
    • Automatically generate a series of fields based on the model class
    • Automatically generated series fields, including * * * unique * * *, * * * max_ Verification of length * * * and other attributes
    • Contains the default implementation of * * * create * * * and * * * update * * *
  • shortcoming
    • The default property of the model class field is not automatically mapped

So what is the serializer associated with the model class? The new serializer base class is used

from rest_framework.serializers import ModelSerializer

For example, a commodity model class

class Goods(models.Model):
    title = models.CharField(max_length=200, verbose_name='Product title')
    description = models.TextField(verbose_name='describe')
    inventory = models.IntegerField(default=0, verbose_name='Inventory')
    price = models.DecimalField(
        max_digits=10, decimal_places=2, verbose_name='commodity price')
    cover = models.CharField(max_length=200, verbose_name='Cover picture')
    issale = models.BooleanField(default=False, verbose_name='Promotion')
    saleprice = models.DecimalField(
        max_digits=10, decimal_places=2, verbose_name='Promotion price')
    ishow = models.BooleanField(default=True,verbose_name='Is it on the shelf')
    createtime = models.DateTimeField(auto_now_add=True, verbose_name='Creation time')
    def __str__(self):
        return self.title
    class Meta:
        db_table = 'goods'

According to the previous normal serialization writing method, you need to synchronize a field and remember to synchronize the field properties, which is very troublesome
But it's easy to use the serializer associated with the model class

  1. First, inherit * * * ModelSerializer * * * base class
  2. Associate the model class through the * * model attribute in the serializer metaclass attribute
  3. The fields that the serializer needs to process are indicated by the fields property in the serializer metaclass property**
class GoodsSer(serializers.ModelSerializer):
    class Meta:
        model = Goods
        fields = '__all__' # Indicates all model class fields
        # exclude = ('createtime',) # Excluded fields
        # read_only_fields = ('title','description') # Fields for serialization only
        # fields = ('title','description','inventory') # Manually specify fields
        # extra_kwargs = {
        #     'price':{'min_value':0, 'required':True},
        # } # Modify the option parameters of the original field

The serializer associated with the model class uses the same method as an ordinary serializer

Use the serializer to return all the current commodity data, or just pass in the * * instance parameter as before. Remember that since it is multiple commodities and not separate data, remember to add the many=True parameter

Model serializer deserialization creation and update

The creation of the model serializer is simpler. There is no need to manually implement the * * * create * * * method. The general process is as follows:

  1. Bind data for serializer, ser=Serializer(data=request.data)
  2. Check data, ser.is_valid()
  3. Storage and warehousing, ser.save()

Create commodity interface

class GoodsCreate(APIView):
    def post(self, request):
        ser = GoodsSer(data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

Note: the field attribute generated automatically by deserialization will not contain the * * * default * * * field attribute in the original model class field

When updating a product data, the model serializer also comes with its own * * * update * * * method

Finer commodity interface

class GoodsUpdate(APIView):
    def put(self, request):
        id_ = request.data.get("id")
        try:
            goods = Goods.objects.get(pk=id_)
        except Goods.DoesNotExist:
            return Response({'msg': 'Update failed,This data does not exist'})

        ser = GoodsSer(instance=goods, data=request.data)
        if ser.is_valid():
            ser.save()
        error = ser.errors
        return Response({'msg': error if error else 'success'})

Comparison between model serializer and ordinary serializer

  • When serializing, pass the model class object into the * * * instance * * * parameter
    • The serialization result is obtained using the data attribute of the serializer object
  • When deserialization is created, the data to be deserialized is passed into the data parameter
    • For deserialization, remember to use * * * is first_ Valid * * * verification
  • During deserialization update, the data object to be updated is passed into * * instance parameter, and the updated data is passed into data parameter
  • The model serializer is more convenient than ordinary serializers, automatically generating serialization mapping fields, * * * create * * * methods, etc
  • Associated foreign key serialization. Remember to add * * * many=True when there are many foreign keys in the field property***

Keywords: Python Django Back-end

Added by thegreatdanton on Thu, 25 Nov 2021 03:25:22 +0200