序列化组件之ModelSerializer类

序列化与反序列功能可以整合成一个类,该类继承ModelSerializer

一、基于ModelSerializer类实现序列化器

例如,我们以及有了一个数据库模型类User

class User(models.Model):
    sex_choice = ((0,"男"),(1,"女"))

    name = models.CharField(max_length=32,unique=True)
    age = models.IntegerField(null=True)
    height = models.DecimalField(max_digits=5,decimal_places=2,null=True)
    sex = models.IntegerField(choices=sex_choice,default=0)
    icon = models.ImageField(upload_to="icon",default="default.png")
    pwd = models.CharField(max_length=32,null=True)

1.1 实现序列化组件

继承ModelSerializer类的资源序列化类,内部包含三部分

  • Meta子类、
  • 局部钩子、
  • 全局钩子
    注:create和update方法ModelSerializer已经重写了,使用不需要重写

在Meta子类中

  • model来绑定关联的Model类
  • fields来设置所有的序列化反序列化字段
  • extra_kwargs来设置系统的校验规则

重要的字段校验规则:

  • read_only,代表该字段只参与序列化
  • write_only,代表该字段只参与反序列化
  • required,代表该字段在反序列化是是否是必填(True)还是选填(False),不能和read_only一起使用(规则冲突)
  • 规则细节:
    如果一个字段有默认值或是可以为空,没设置required规则,默认为False,反之默认值为True
    如果一个Model字段即没有设置read_only也没设置write_only,该字段默认参与序列化及反序列化

自定义序列化字段:

  • 在Model类中,定义方法属性(可以返回特殊值,还可以完成连表操作),在序列化类的fields属性中可以选择性插拔
class User(models.Model):
    # 自定义插拔序列化字段:替换了在Serializer类中自定义的序列化字段(SerializerMethodField)
    # 自定义插拔序列化字段一定不参与反序列化过程
    @property
    def gender(self):
        return self.get_sex_display()

自定义反序列化字段:

  • 在类中,自定义校验字段,校验规则也只能在声明字段时设置,自定义的反序列化字段(如re_pwd)
'''serializers.py'''

# 重点 ModelSerializer
from rest_framework.serializers import ModelSerializer
from .. import models
# 整合序列化与反序列化
class UserModelSerializer(ModelSerializer):
    # 将序列化类与Model类进行绑定
    # 设置序列化与反序列化所有字段(并划分序列化字段与反序列化字段)
    # 设置反序列化的局部与全局钩子

    # 自定义反序列化字段,校验规则只能在声明自定义字段时设置,且一定是write_only
    re_pwd = serializers.CharField(min_length=3, max_length=64, write_only=True)

    class Meta:
        # 用model来绑定关联的Model类
        model = models.User
        # 用fields来设置所有的序列化反序列化字段
        fields = ['name',"age","pwd","re_pwd","gender","sex"]
        # 用extra_kwargs来设置系统的校验规则,只有反序列化的时候能用到
        extra_kwargs = {
            "name":{
                "required":True,
                'min_length': 3,
                'error_messages': {
                    'min_length': '太短'
                }
            },
            "age": {
                "required": True,  # 数据库有默认值或可以为空字段,required默认为False
                'min_value': 0,
            },
            "pwd": {
                "required": True,  # 数据库有默认值或可以为空字段,required默认为False
                "write_only":True,
            },
            "gender": {
                "read_only":True,
            },
            "sex": {
                "write_only":True,
            },
        }

    def validate_name(self, value):
        if 'g' in value.lower():
            raise serializers.ValidationError('名字中不能有g')
        return value

    def validate(self, attrs):
        pwd = attrs.get('pwd')
        re_pwd = attrs.pop('re_pwd')
        if pwd != re_pwd:
            raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
        return attrs
    # ModelSerializer已经帮我们重写了入库方法

1.2 使用序列化组件

'''views.py'''

from . import models
from .utils import serializers
from rest_framework import status

'''ModelSerializer类'''
class UserV2APIView(APIView):
    def get(self,request,*args,**kwargs):
        pk = kwargs.get("pk")
        if pk:
            user_obj = models.User.objects.filter(pk=pk).first()
            if not user_obj:
                return Response({
                    'status': 1,
                    'msg': '单查 error'
                })

            # 完成序列化
            user_data = serializers.UserModelSerializer(user_obj, many=False).data
            return Response({
                'status': 0,
                'msg': '单查 ok',
                'results': user_data
            })
        else:
            user_query = models.User.objects.all()
            # 完成序列化
            user_list_data = serializers.UserModelSerializer(user_query, many=True).data
            return Response({
                'status': 0,
                'msg': '群查 ok',
                'results': user_list_data
            })


    def post(self,request,*args,**kwargs):
        request_data = request.data

        user_ser = serializers.UserModelSerializer(data=request_data)

        # 校验失败,直接抛异常,反馈异常信息给前台,只要校验通过,代码才会往下执行
        result = user_ser.is_valid()
        if result:
            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
            }, status=status.HTTP_400_BAD_REQUEST)

猜你喜欢

转载自www.cnblogs.com/XuChengNotes/p/11902095.html