rest_framework serialization and deserializationOne

rest_framework serialization and deserializationOne

Custom serialization process

The process of custom serialization, single check and group check of data, serialization process: ORM operation to get the data, and then serialize the data into data that can be used by the front desk and return it to the front desk.

from rest_framework.response import Response
from django.conf import settings
from rest_framework.views import APIView
from. import models


class UserV1APIView(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_dic = models.User.objects.filter(is_delete=False,pk=pk).values('username','sex','img').first()
                                                #Serialized
            if not user_dic:
                return Response({
                    'status':1,
                    'msg':'pk error'
                },status=400)
            user_dic['img'] ='%s%s%s'%(settings.BASE_URL,settings.MEDIA_URL,user_dic.get('img'))
            return Response({
                'status': 0,
                'msg':'ok',
                'results':user_dic
            })


        else:
            user_query = models.User.objects.filter(is_delete=False).values('username','sex','img')
                                                                        #Serialized

            for user_dic in user_query:#user_query list set dictionary
                user_dic['img'] ='%s%s%s'%(settings.BASE_URL,settings.MEDIA_URL,user_dic.get('img'))
            user_list = list(user_query)
            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_list
            })

Use rest_framework's serialization module serializers to serialize and deserialize view data

Serialization

1) Set the serialization field, the field name and field type should correspond to the attribute name of the model class to be processed (only the types involved in serialization do not need to set conditions)

2) There are fields in the model class, but there is no corresponding field in the serialization. This type of field does not participate in the serialization

3) Custom serialization field (Method 1), the field type is SerializerMethodField(), the value is provided by the get_custom field name (self, model_obj) method, and the general value is related to the model object (model_obj) involved in serialization

#View class
from. import serializers
class UserV2APIView(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
            if not user_obj:
                return Response({
                    'status': 1,
                    'msg':'pk error'
                }, status=400)

            user_ser = serializers.UserSerializer(user_obj,many=False)#many defaults to False

            # user_dic['img'] ='%s%s%s'% (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
            user_obj_data = user_ser.data
            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_obj_data
            })
        else:
            # Encapsulate the fields provided by the object and the entire serialization process to form a serialization class
            user_query = models.User.objects.filter(is_delete=False).all()

            user_ser = serializers.UserSerializer(user_query, many=True)
            user_list_data = user_ser.data

            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_list_data
            })
     
    
#Custom serialization class serializers
from rest_framework import serializers
from django.conf import settings
from. import models


class UserSerializer(serializers.Serializer):
    # 1) The field name and field type should correspond to the processed model class
    # 2) Fields that are not provided will not participate in serialization to the front desk
    # 3) You can customize the serialization field, use method serialization, the method fixes two parameters, the second parameter is the model object that participates in the serialization

    username = serializers.CharField()

    # It is not recommended that the custom field name be the same as the database field name, it is better to use the return value of the get_custom field name method to provide the field value
    # sex = serializers.SerializerMethodField() # It is not recommended to name it like this
    gender = serializers.SerializerMethodField()
    def get_gender(self,obj):
        return obj.get_sex_display()

    #Note: In the advanced serialization and advanced view classes, drf helps us process sub-resources such as pictures by default
    icon = serializers.SerializerMethodField()
    def get_icon(self,obj):
        return'%s%s%s'% (settings.BASE_URL, settings.MEDIA_URL, obj.img)

Deserialization

1) There is no difference between the system check field and the custom check field definition:

Field = serializers. field type (condition)

2) Custom check fields cannot write data directly to the database, they are only responsible for the check before the data is written to the database.

3) All fields can be verified by setting corresponding local hooks. The setting method of local hooks: validate_ field name (self, field value value)

Rule: The verification pass directly returns the value, the verification fails, the verification failure message is thrown: ValidationError('error information')

4) A serialization class has a global hook that can perform global verification on all fields. The method of use: validate(self, dictionary of all field values ​​attrs)

Rule: return attrs directly if verification is successful, and throw verification failure message if verification fails: ValidationError({'Exception Field','Error Information'})

5) Rewrite the create method to write the new data into the database, and return the successfully written data object

6) Rewrite the update method to write the modified data into the database, and return the successfully modified data object

#View class
from. import serializers
class UserV2APIView(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
            if not user_obj:
                return Response({
                    'status': 1,
                    'msg':'pk error'
                }, status=400)

            user_ser = serializers.UserSerializer(user_obj,many=False)#many defaults to False

            # user_dic['img'] ='%s%s%s'% (settings.BASE_URL, settings.MEDIA_URL, user_dic.get('img'))
            user_obj_data = user_ser.data
            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_obj_data
            })
        else:
            # Encapsulate the fields provided by the object and the entire serialization process to form a serialization class
            user_query = models.User.objects.filter(is_delete=False).all()

            user_ser = serializers.UserSerializer(user_query, many=True)
            user_list_data = user_ser.data

            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_list_data
            })

    #单增
    def post(self,request,*args,**kwargs):
        request_data = request.data
        user_ser = serializers.UserDeSerializer(data=request_data)
                                #Call deserialization class
        if user_ser.is_valid():
            user_obj = user_ser.save()#Write to database
            return Response({
                'status':0,
                'msg':'ok',
                'results':serializers.UserSerializer(user_obj).data
                # Return the reserialized data of the user object obtained in the library to the front desk
            })

        else:
            return Response({
                'status':1,
                'msg':user_ser.errors,
            })
#Inherit the serializers.Serializer class custom deserialization class of drf
class UserDeSerializer(serializers.Serializer):

    #drf Check field
    username = serializers.CharField(min_length=3,max_length=16,error_messages={
        'min_length':'too short',
        'max_length':'too long'
    })
    password = serializers.CharField(min_length=3,max_length=16)

    # Fields not defined here do not participate in deserialization. If defined here, they must participate in deserialization (but you can not deserialize by setting required=False)
    # required=False field, if the front desk does not provide data, the default value is used, then the field will not be deserialized; if the front desk provides the data of the field, the data will be verified, and the data will be verified after verification Deserialize, and then write it to the database; no field is defined here, regardless of whether the front desk passes a value to the field, the default value is written to the database
    sex = serializers.BooleanField(required=False)

    # The data type and field name of the custom check field are the same as the fields in the models class, but the check field only checks the data
    re_password = serializers.CharField(min_length=3,max_length=16)

    # Partial hook:
    # Method validate_validated field name (self, validated field data)
    # Validation rule: the value will be returned directly after the validation, and the validation failure message will be thrown if the validation fails
    def validate_username(self,value):
        if'b' in value.lower():
            raise serializers.ValidationError('A cannot appear in the name')
        return value

    def validate(self, attrs):
        re_password = attrs.pop('re_password')#pop will first take out the content to be popped, and then pop
        password = attrs.get('password')
        if password != re_password:
            raise serializers.ValidationError({'re_password':'The two passwords are not consistent'})
        return attrs

    # In the view class, call the save method of the serialization class to write data to the database, and the save method will call the create and update methods of the Serializer class to write the data to the database.
    # But the Serializer class only defines empty create, update and other methods of operating the database. We need to rewrite these methods of the database to complete the operation of writing data to the database.
  
    def create(self, validated_data):

        return models.User.objects.create(**validated_data)

    # instance is the object to be modified, validated_data represents the data used to modify the instance after verification
    def update(self, instance:models.User, validated_data):
        #Do not modify user name
        validated_data.pop('username')
        models.User.objects.filter(pk=instance.id).update(**validated_data)
        return instance

Use ModelSerializer model class to complete serialization and deserialization

If we want to use the serializer corresponding to the Django model class, DRF provides us with the ModelSerializer model class serializer to help us quickly create a Serializer class.

ModelSerializer is the same as regular Serializer, but provides:

  • Automatically generate a series of fields based on the model class
  • Automatically generate validators for Serializer based on the model class, such as unique_together
  • Contains the implementation of the default create() and update()

Serialization and deserialization are achieved by inheriting the ModelSerializer class:

1) The serialization class inherits ModelSerializer, so it needs to be configured in the configuration class Meta

2) Model configuration: binding serialization related Model table

3) Fields configuration: use pluggable settings for all fields involved in serialization and deserialization

4) Extra_kwargs configuration: There are three types of system fields: read-only (read_only), write-only (write_only), readable and writable (when not set)

Whether the field must be filled in: required
Optional field: configure in extra_kwargs, no need to set required, default required=False
Read-only and write-only operations are used to participate in the serialization and deserialization of the fields, and do not directly affect the read and write of the database, so we can set the confirmation password and other fields to write-only, when using the global hook to take it out Remove it from the hook's attrs while proceeding.

5) Custom serialization fields: The first type (not recommended): Use SerializerMethodField() in the serialization class to achieve

The second (advocate): use @property to achieve in the model class, pluggable such as the following model class and serialization class
#Model Class
username = models.CharField(max_length=64, verbose_name='username', blank=True, unique=True)
    password = models.CharField(max_length=64, verbose_name='password')
    sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='gender')
    img = models.ImageField(upload_to='img', default='img/default.png', verbose_name='avatar')
    # During development, the data will not be deleted directly, but controlled by the field
    is_delete = models.BooleanField(default=False, verbose_name='Whether to log out')
    # Database data storage, generally records the first storage time of the data, sometimes it also records the last update time
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='Created Time')

    # The second type of custom serialization field (pluggable, recommended)
    @property
    def gender(self):
        return self.get_sex_display()

    @property
    def icon(self):
        from django.conf import settings
        return'%s%s%s'% (settings.BASE_URL, settings.MEDIA_URL, self.img)


    class Meta: # Configuration class, which provides configuration information for the class to which it belongs
        db_table ='user'
        verbose_name_plural ='User table'

The so-called pluggable means that the field can be serialized and deserialized by default when it is added to the fields, but the premise is that the fields in the models must be customized. If it is a custom serialized field, the default is read_only, and cannot be modified, customized If the field is not pluggable, it can be deserialized but only deserialized (for data verification) cannot be written to the database.

#Serialization class
class UserModelSerializer(serializers.ModelSerializer):
    #Validation rules can only be set at the time of definition, or set in the hook, and the setting in extra_kwargs is invalid
    re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)
    class Meta:
        model = models.User
        # fields adopt pluggable settings for all participating serialization and deserialization fields
        fields = ('username','gender','icon','password','sex','re_password')
        extra_kwargs = {
            'username': {# The system field does not set read_only and write_only, both will participate by default
                'min_length': 3,
                'max_length': 10,
                'error_messages': {
                    'min_length':'too short',
                    'max_length':'too long'
                }
            },
            'gender': {
                'read_only': True, # The custom serialization field is read_only by default, and cannot be modified, and can be omitted
            },
            'password': {
                'write_only': True,
            },
            'sex': {# The fields with default values ​​like sex are optional fields ('required': True can make them required fields)
                'write_only': True,
                #'required': True
            }
        }

6) Custom deserialization fields:

#It is the same as the Serializer class, and the verification rules can only be set at the time of definition, or set in the hook, and the setting in extra_kwargs is invalid
 re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)

#Custom deserialization field is the same as system field setting rules, so write_only must be set to True

7) Local hooks, global hooks are the same as the Serializer class

   # The local and global hooks are the same as the Serializer class, and are indented the same as Meta
    def validate_username(self, value):
        if'g' in value.lower():
            raise serializers.ValidationError('There can be no g in the name')
        return value

    def validate(self, attrs):
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if password != re_password:
            raise serializers.ValidationError({'re_password':'The two passwords are not consistent'})
        return attrs
    #Verification rules: Local hook verification success returns value directly, failure message throws failure information,
    #Global hook verification success returns attrs, failure throws verification failure information

8) No need to rewrite create and update methods

The create and update methods of ModelSerializer are already written and will be called when the user_obj = user_ser.save() method is executed.

The complete view class, serialization class, and models class codes that are serialized and deserialized by inheriting the ModelSerializer class are as follows. The code realizes the query to the database through the browser and the single increase of data:

#View class
class UserV3APIView(APIView):
    # Single check group check
    def get(self, request, *args, **kwargs):
        pk = kwargs.get('pk')
        if pk:
            user_obj = models.User.objects.filter(is_delete=False, pk=pk).first()
            if not user_obj:
                return Response({
                    'status': 1,
                    'msg':'pk error',
                }, status=400)

            user_ser = serializers.UserModelSerializer(user_obj, many=False)
            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_ser.data
            })
        else:
            user_query = models.User.objects.filter(is_delete=False).all()

            user_ser = serializers.UserModelSerializer(user_query, many=True)

            return Response({
                'status': 0,
                'msg':'ok',
                'results': user_ser.data
            })

    # Single increase
    def post(self, request, *args, **kwargs):
        user_ser = serializers.UserModelSerializer(data=request.data)
        if user_ser.is_valid():
            # Warehousing
            user_obj = user_ser.save()
            return Response({
                'status': 0,
                'msg':'ok',
                'results': serializers.UserModelSerializer(user_obj).data
            })
        else:
            return Response({
                'status': 1,
                'msg': user_ser.errors,
            })
#Serialization class
class UserModelSerializer(serializers.ModelSerializer):
    # The first type of custom serialization field: this field must be set in fields
    # gender = serializers.SerializerMethodField()
    # def get_gender(self, obj):
    # return obj.get_sex_display()


    # The usage of the custom deserialization field is the same as the Serializer class, and the rules can only be set in this statement or in the hook. The setting in extra_kwargs is invalid.
    # Note: Custom deserialization fields and system fields have the same setting rules, so write_only must be set
    re_password = serializers.CharField(min_length=3, max_length=16, write_only=True)

    class Meta:
        model = models.User
        # fields adopt pluggable settings for all participating serialization and deserialization fields
        fields = ('username','gender','icon','password','sex','re_password')
        extra_kwargs = {
            'username': {# The system field does not set read_only and write_only, both will participate by default
                'min_length': 3,
                'max_length': 10,
                'error_messages': {
                    'min_length':'too short',
                    'max_length':'too long'
                }
            },
            'gender': {
                'read_only': True, # The custom serialization field is read_only by default, and cannot be modified, and can be omitted
            },
            'password': {
                'write_only': True,
            },
            'sex': {# The fields with default values ​​like sex are optional fields ('required': True can make them required fields)
                'write_only': True,
                #'required': True
            }
        }


    # Local and global hooks have the same usage as the Serializer class, and are indented the same as Meta
    def validate_username(self, value):
        if'g' in value.lower():
            raise serializers.ValidationError('There can be no g in the name')
        return value

    def validate(self, attrs):
        password = attrs.get('password')
        re_password = attrs.pop('re_password')
        if password != re_password:
            raise serializers.ValidationError({'re_password':'The two passwords are not consistent'})
        return attrs
#Model Class
from django.db import models

class User(models.Model):
    SEX_CHOICES = (
        (0,'Female'),
        (1,'Male'),
    )

    username = models.CharField(max_length=64, verbose_name='username', blank=True, unique=True)
    password = models.CharField(max_length=64, verbose_name='password')
    sex = models.IntegerField(choices=SEX_CHOICES, default=0, verbose_name='gender')
    img = models.ImageField(upload_to='img', default='img/default.png', verbose_name='avatar')
    # During development, the data will not be deleted directly, but controlled by the field
    is_delete = models.BooleanField(default=False, verbose_name='Whether to log out')
    # Database data storage, generally records the first storage time of the data, sometimes it also records the last update time
    created_time = models.DateTimeField(auto_now_add=True, verbose_name='Created Time')

    # The second type of custom serialization field (pluggable, recommended)
    @property
    def gender(self):
        return self.get_sex_display()

    @property
    def icon(self):
        from django.conf import settings
        return'%s%s%s'% (settings.BASE_URL, settings.MEDIA_URL, self.img)


    class Meta: # Configuration class, which provides configuration information for the class to which it belongs
        db_table ='user'
        verbose_name_plural ='User table'

    def __str__(self): # Don’t link tables here, for example, the admin page may crash
        return self.username
Reference: https://cloud.tencent.com/developer/article/1561960 rest_framework serialization and deserialization 1-Cloud + Community-Tencent Cloud