zoukankan      html  css  js  c++  java
  • DRF单表序列化

    DRF单表序列化

    ​ 后台的数据多以后台类的对象存在,经过序列化后,就可以格式化成能返回给前台的数据。

    ​ 定义一个全局models:

    ​ models.py:

    from django.db import models
    
    class User(models.Model):
        CHOICES_SEX = ((0, '男'), (1, '女'))
        name = models.CharField(max_length=64)
        age = models.IntegerField(default=0)
        height = models.DecimalField(max_digits=5, decimal_places=2, default=0)
        icon = models.ImageField(upload_to='icon', default='default.png')
        sex = models.IntegerField(choice=CHOICE_SEX, default=0)
        # 若以迁移数据库后新增自选,需要允许为空,或者设置默认值,假定pwd为新增字段
        pwd = models.CharField(max_length=64, null=Ture)
        
        # 自定义插拔序列化字段:替换了在Serializer类中自定义的序列化字段(SerializerMethodField)
        # 自定义插拔序列化字段一定不参与反序列化过程
        @property
        def gender(self):
            return self.get_sex_display()
        
        class Meta:
            db_table = 'ob_user'
            verbose_name = '用户表'
            verbose_name_plural = verbose_name
            
        def __str__(self):
            return self.name
    

    一、Serializer组件

    ​ 序列化步骤:

    ​ 1、ORM操作数据库拿到资源数据。

    ​ 2、格式化成能返回给前台的数据(序列化)。

    ​ 3、返回格式化后的数据。

    ​ views.py:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from . import models, serializers
    from rest_framework import status
    
    class UserAPIView(APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            
            if pk:
            	user_obj = models.User.object.filter(pk=pk).first()
                if not user_obj:
                    return Response({
                        'status' : 1,
                        'msg': '单查 error'
                    })
                # 完成序列化
                user_ser= serializers.UserSerializer(user_obj, many=False)
                user_data = user_ser.data
                
                return Response({
                    'status': 0,
                    'msg': '单查 ok',
                    'results': user_data
                })
            # 多查
            user_query = models.User.objects.all()
            # 完成序列化
            user_list_data = serializers.UserSerializer(user_query, many=Ture).data
            return Response({
                'status': 0,
                'msg': '群查 ok',
                'results': user_list_data
            })
    

    ​ 反序列化:

    ​ 1、从请求对象中拿到前台的数据。

    ​ 2、校验前台数据是否合法。

    ​ 3、反序列化成后台Model对象与数据库交互。

    	def post(self, request, *args, **kwargs):
            request_data = request.data
            
            # 反序列化目的:封装数据的校验过程,以及数据库交互的过程
            user_ser = serializer.UserDeserializer(data=request_data)
        	# 调用反序列化的校验规则:系统规则,自定义规则(局部钩子,全局钩子)
            result = user_ser.isvalid()
            
            if result:
                # 校验通过,可以与数据库进行交互:增(create),改(update)
                user_obj = user_ser.save()
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': serializers.UserSerializer(user_obj).data
                })
            else:
                # 校验失败,返回错误信息
                return Response({
                    'status': 1,
                    'msg': user_ser.errors
                }, status=status.HTTP_400_BAD_REQUEST)
    

    ​ 数据校验:

    ​ serializers.py:

    from rest_framework import serializers
    
    class UserSerializer(serializers.Serializer):
        
        # model已有的属性字段校验
        #   如果要参与序列化,名字一定要与model的属性同名
        #   如果不参与序列化的model属性,在序列化类中不做声明
        name = serializers.CharField()
        age = serializers.IntegerField()
        height = serializers.DecimalField(max_digits=5, decimal_places=2)
        
        # 自定义序列化字段,序列化的属性值由方法来提供,
        #   方法的名字:固定为 get_属性名,
        #   方法的参数:序列化对象,序列化的model对象
        #   强烈建议自定义序列化字段名不要与model已有的属性名重名
        gender = serializers.SerializerMethodField()
        def get_gender(self, obj)
        	return obj.get_sex_display()
        
    from . import models
    
    class UserDeserializer(serializers.Serializer):
        # 系统校验规则
        # 系统必须反序列化的字段
        # 序列化属性名不是必须与model属性名对应,但是与之对应会方便序列化将校验通过的数据与数据库进行交互
        name = serializers.CharField(min_length=3, max_length=64, error_messages={
            'required': '姓名必填',
            'min_length': '太短',
        })
        pwd = serializers.CharField(min_length=3, max_length=64)
        
        # 系统可选的反序列化字段:没有提供不进行校验(数据库中有默认值或可以为空),提供了就进行校验
        age = serializers.IntegerField(min_value=0, max_value=150, required=False)
        # 自定义反序列化字段:一定参与校验,且要在校验过程中,将其从入库的数据中取出,剩余与model对应的数据才会入库
        re_pwd = serializers.CharField(min_length=3, max_length=64)
    
        # 自定义校验规则:局部钩子,全局钩子
        # 局部钩子:validate_字段名(self, 字段值)
        # 规则:成功返回value,失败抛异常
        def validate_name(self, value):
            if len(value) < 2:
                raise serializers.ValidationError('不能短于两位')
            return value
        
        # 全局钩子:validate(self, 所有校验的数据字典)
        # 规则:成功返回attrs,失败抛异常
        
        def validata(self, attrs):
            pwd = attrs.get('pwd')
            re_pwd = attrs.pop('re_pwd')
            if pwd != re_pwd:
                raise serializers.ValidationError({'re_pwd': '两次密码不一致'})
            retuen attrs
            
        # create重写,完成入库
        def create(self, validated_data):
            return models.User.objects.create(**validated_data)
    

    二、ModelSerializer组件

    ​ 如果要使用序列化器对应的是Django的模型类,DRF提供了ModelSerializer模
    型类序列化器,可以快速创建一个Serializer类。

    ​ ModelSerializer与常规的Serializer相同,但提供了:

    ​ 1、基于模型类自动生成一系列字段

    ​ 2、基于模型类自动为Serializer生成validators,比如unique_together

    ​ 3、包含默认的create()和update()的实现

    ​ views.py:

    from rest_framework.views import APIView
    from rest_framework.response import Response
    from . import models, serializers
    from rest_framework import status
    
    class UserAPIView(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
                })
            # 群查
            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)
    

    ​ 数据校验:

    ​ modelserializer.py

    from rest_framework.serializers import ModelSerializer
    from . import models
    # 整合序列化与反序列化
    class UserModelSerizlizer(ModelSerializer):
        # 将序列化类与Model类进行绑定
        # 设置序列化与反序列化所有字段(并划分序列化字段与反序列化字段)
        # 设置反序列化的局部与全局钩子
        
        # 自定义反序列化字段,校验规则只能在声明自定义反序列化字段时设置,且一定是write_only
        re_pwd = serializers.CharField(min_length=3, max_length=64, write_only=True)
        class Meta:
            model = models.User
            fields = ['name', 'age', 'height', 'gender', 'pwd', 're_pwd']
    		extra_kwargs = {
                'name': {
                    'required': True,
                    'min_length': 3,
                    'error_messages': {
                        'min_length': '太短'
                    }
                },
                'age': {
                    'required': Ture,  # 数据库有默认值或可以为空字段,required默认为False
                    'min_value': 0
                },
                'pwd': {
                    required: Ture,
                    'write_only': Ture,  # 只参与反序列化
                },
                'gender': {
                    'reader_only': Ture,  # 只参与序列化
                },
            }
            
    	def validate_name(self, value):
            if len(value) < 2:
                raise serializers.ValidationError('不能短于两位')
            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
        
        # 无需重写create,ModelSerializer已封装好了
    

    三、单表序列化总结

    3.1 序列化

    一、视图类的三步操作

    ​ 1)ORM操作数据库拿到资源数据

    ​ 2)格式化(序列化)成能返回给前台的数据

    ​ 3)返回格式化后的数据

    二、视图类的序列化操作

    ​ 1)直接将要序列化的数据传给序列化类

    ​ 2)要序列化的数据如果是单个对象,序列化的参数many为False,数据如果是多个对象(list,queryset)序列化的参数many为True

    三、序列化类

    ​ 1)model了中要反馈给前台的字段,在序列化类中要进行声明,属性名必须就是model的字段名,且Field类型也要保持一致(不需要明确规则)

    ​ 2)model了中不需要反馈给前台的字段,在序列化类中不需要声明(省略)

    ​ 3)自定义序列化字段用 SerializerMethodField() 作为字段类型,该字段的值来源于 get_自定义字段名(self, obj) 方法的返回值

    3.2 反序列化

    一、视图类的三步操作

    ​ 1)从请求对象中拿到前台的数据

    ​ 2)校验前台数据是否合法

    ​ 3)反序列化成后台Model对象与数据库交互

    二、视图类的反序列化操作

    ​ 1)将要反序列化的数据传给序列化类的data参数

    ​ 2)要反序列化的数据如果是单个字典,反序列化的参数many为False,数据如果是多个字典的列表,反序列化的参数many为True

    三、反序列化类

    ​ 1)系统的字段,可以在Field类型中设置系统校验规则(name=serializers.CharField(min_length=3))

    ​ 2)required校验规则绝对该字段是必校验还是可选校验字段(默认required为True,数据库字段有默认值或可以为空的字段required可以赋值为False)

    ​ 3)自定义的反序列字段,设置系统校验规则同系统字段,但是需要在自定义校验规则中(局部、全局钩子)将自定义反序列化字段取出(返回剩余的数据与数据库交互)

    ​ 4)局部钩子的方法命名 validate_属性名(self, 属性的value),校验规则为 成功返回属性的value 失败抛出校验错误的异常

    ​ 5)全局钩子的方法命名 validate(self, 所有属性attrs),校验规则为 成功返回attrs 失败抛出校验错误的异常

    3.3 单表序列化

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

    ​ 2)继承ModelSerializer类的资源序列化类,内部包含三部分 Meta子类、局部钩子、全局钩子

    ​ 注:create和update方法ModelSerializer已经重写了,使用不需要重写

    ​ 3)在Meta子类中: 用model来绑定关联的Model类 用fields来设置所有的序列化反序列化字段 用extra_kwargs来设置系统的校验规则

    ​ 4)重要的字段校验规则:

    ​ read_only校验规则,代表该字段只参与序列化

    ​ write_only校验规则,代表该字段只参与反序列化

    ​ required校验规则,代表该字段在反序列化是是否是必填(True)还是选填(False),不能和read_only一起使用(规则冲突)

    ​ 规则细节:

    ​ 如果一个字段有默认值或是可以为空,没设置required规则,默认为False,反之默认值为True

    ​ 如果一个Model字段即没有设置read_only也没设置write_only,该字段默认参与序列化及反序列化

    ​ 5)自定义序列化字段:在Model类中,定义方法属性(可以返回特殊值,还可以完成连表操作),在序列化类的fields属性中可以选择性插拔

    ​ 6)自定义反序列化字段:在Serializer类中,自定义校验字段,校验规则也只能在声明字段时设置,自定义的反序列化字段(如re_pwd),必须设置write_only为True

  • 相关阅读:
    iOS resign code with App Store profile and post to AppStore
    HTTPS科普扫盲帖 对称加密 非对称加密
    appid 评价
    使用Carthage安装第三方Swift库
    AngularJS:何时应该使用Directive、Controller、Service?
    xcode7 The operation couldn't be completed.
    cocoapods pod install 安装报错 is not used in any concrete target
    xcode7 NSAppTransportSecurity
    learning uboot how to set ddr parameter in qca4531 cpu
    learning uboot enable protect console
  • 原文地址:https://www.cnblogs.com/tangceng/p/11901117.html
Copyright © 2011-2022 走看看