Python test development django-rest-framework-88. Deserialization (ModelSerializer) verification of incoming parameters

Foreword

serializers.Serializer can serialize fields in the model model, and two methods, create and update, must be written. ModelSerializer can be regarded as an upgraded version of Serializer, which is more powerful and convenient.
In fact, the ModelSerializer class inherits the Serializer class

Serialization

Serialization is to convert the data in the database into json format and return it to the user. For details, please refer to the previous article https://www.cnblogs.com/yoyoketang/p/11538172.html
Design a Goods product table in models.py, which contains multiple fields and multiple data types.

from django.db import models
# Create your models here.
# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/



class Goods(models.Model):
    """Product List"""
    goods_name = models.CharField(max_length=30,
                                  default="",
                                  verbose_name="product name")
    goods_code = models.CharField(max_length=30,
                                  unique=True,
                                  verbose_name="Product code")
    merchant_id = models.CharField(max_length=30,
                                   default="",
                                   blank=True, null=True,
                                   verbose_name="merchant ID")
    merchant_name = models.CharField(max_length=30,
                                     default="",
                                     blank=True, null=True,
                                     verbose_name="merchant name")
    goods_price = models.FloatField(blank=True, null=True,
                                    default=0,
                                    verbose_name="Product price")
    goods_stock = models.IntegerField(blank=True, null=True,
                                      default=0,
                                      verbose_name="item inventory")
    goods_groupid = models.IntegerField(blank=True, null=True,
                                        default=0,
                                        verbose_name="Product group")
    goods_status = models.IntegerField(choices=(
                                                (0, 'Removed'),
                                                (1, 'For Sale')
                                               ),
                                       default=1,
                                       verbose_name="0 off the shelves 1 on sale")

    price = models.FloatField(blank=True, null=True,
                              default=0,
                              verbose_name="cost price")

    create_time = models.DateTimeField(auto_now_add=True, verbose_name="Add Time")
    update_time = models.DateTimeField(auto_now=True, verbose_name="Modification time")

    class Meta:
        verbose_name_plural = 'commodity'
        verbose_name = "Product information"

    def __str__(self):
        return self.goods_code

view view

The view inherits drf’s APIView. Two methods are written here. Get queries all products and returns json data after serialization.
The post request is to create a product.

from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
from rest_framework.authentication import TokenAuthentication
from .models import Goods

# Create your views here.
# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    class Meta:
        model = Goods
        fields = '__all__' # Return all fields
        # exclude does not include certain fields
        # exclude = ["price"]


class GoodsAPIView(APIView):
    """Product View"""
    permission_classes = (AllowAny,) # AllowAny allows all users

    def get(self, request, *args, **kwargs):
        """returns all """
        goods = Goods.objects.all() # Query all
        serializer = GoodsSerializer(instance=goods, many=True)

        return Response({
            "code": 0,
            "msg": "success!",
            "data": serializer.data
        })


    def post(self, request, *args, **kwargs):
        """submit data"""
        verify_data = GoodsSerializer(data=request.data)
        if verify_data.is_valid():
            save = verify_data.save()
            return Response({
                "code": 0,
                "msg": "success!",
                "data": GoodsSerializer(instance=save).data
            })
        else:
            return Response({
                "code": 10086,
                "msg": "Illegal parameter",
                "data": verify_data.errors
            })

urls.py configures access routing

from django.conf.urls import url
from yoyo import views

urlpatterns = [
    url('^api/v1/goods/$', views.GoodsAPIView.as_view()),
]

Serialization and Deserialization

What is serialization?

When users need to query data, the data in the database is converted into the json data we need. This process is serialization.

Instantiate the GoodsSerializer object in the get method and pass 2 parameters

  • Instance is the queryset object of the query, or it can be the object object of a single Goods
  • many If it is a queryset object, you need to bring many=True, indicating that it is a list with multiple data. If it is a single object object, you do not need this parameter.
def get(self, request, *args, **kwargs):
        """returns all """
        goods = Goods.objects.all() # Query all
        serializer = GoodsSerializer(instance=goods, many=True)

The above process is serialization. After serialization, the data is output serializer.data

What is deserialization?

When users add products, they need to save the data to the database. In this process, we need to first verify whether it is legal.

For the data passed in by the user, we need to clean it first, because the user may pass some fields that are not in the database table, and we do not need these, so we can use GoodsSerializer(data=request.data)

  • data The parameters passed in by the user are obtained through request.data. request.data is actually the same as the previous request.POST to obtain the data passed by the user.
  • is_valid() Verifies whether the data is legal
  • save() must call is_valid() before saving, and return a Goods object after saving.
def post(self, request, *args, **kwargs):
        """submit data"""
        verify_data = GoodsSerializer(data=request.data)

In the above process, the data passed by the user is first cleaned, the legality of the data is verified, and then the process is stored in the database, which is deserialization.

Item required to verify user data required=True

Those who have read the interface document should know that some parameters are required and some are not required. Then we can control the required and non-required fields in GoodsSerializer
For details, please refer to the previous article https://www.cnblogs.com/yoyoketang/p/14291206.html

class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    #Required fields
    goods_code = serializers.CharField(required=True)
    goods_stock = serializers.IntegerField(required=True)

    class Meta:
        model = Goods
        fields = '__all__' # Return all fields

When serializing, set goods_code and goods_stock as required fields. Then when adding goods, you will be prompted if they are not passed.

{"goods_code":["This field is required."],"goods_stock":["This field is required."]}}

Validation ignores some fields read_only=True

If there are some fields that I don’t want users to modify when creating a product, such as goods_status (product status), the default is for sale,

You don’t want users to set off the shelf when creating, so you can ignore the goods_status field and set read_only=True

# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    #Required fields
    goods_code = serializers.CharField(required=True)
    goods_stock = serializers.IntegerField(required=True)

    # Ignore the field and set read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    class Meta:
        model = Goods
        fields = '__all__' # Return all fields

Now no matter what goods_status is passed, it will not affect the saved result.

Verify string and integer range

Verify goods_code string length is 8-15 digits, verify goods_stock integer range is 1-10000

class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    #Required fields
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # Ignore the field and set read_only=True
    goods_status = serializers.IntegerField(read_only=True)



    class Meta:
        model = Goods
        fields = '__all__' # Return all fields

At this time, the incoming string and integer range will be verified.

Customized verification field

If I want to name the user’s product code, it must start with sp and write a separate verification method for a certain field. You can customize validate_

  • The value parameter is the data passed in
  • The exception thrown by raise will be serializers.ValidationError(“goods_code does not start with sp”) and will be displayed in verify_data.errors
# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    #Required fields
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # Ignore the field and set read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    def validate_goods_code(self, value):
        """Validate field validate_<Field>"""
        if not value.startswith("sp"):
            raise serializers.ValidationError("goods_code does not start with sp")
        return value

    class Meta:
        model = Goods
        fields = '__all__' # Return all fields

Multiple field verification

If I want to check that goods_price (product sales price) cannot be less than (price) cost price, if any operation sets the product price lower than the cost price, it will be a big loss!
This involves mutual verification of the two values of the incoming parameters.

# Author-Shanghai Youyou QQ communication group: 717225969
# blog address https://www.cnblogs.com/yoyoketang/


class GoodsSerializer(serializers.ModelSerializer):
    """Serialized product models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    #Required fields
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # Ignore the field and set read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    def validate_goods_code(self, value):
        """Validate field validate_<Field>"""
        if not value.startswith("sp"):
            raise serializers.ValidationError("goods_code does not start with sp")
        return value

    def validate(self, attrs):
        """Custom verification"""
        goods_price = attrs.get('goods_price', 0)
        price = attrs.get('price', 0)
        if goods_price < price:
            raise serializers.ValidationError('goods_price cannot be less than price')
        return attrs

    class Meta:
        model = Goods
        fields = '__all__' # Return all fields