• drf框架(三)


    序列化组件

    Serializer(偏底层,了解)
    
    ModelSerializer(重点)
    
    ListModelSerializer(辅助群改)
    

    1.Serializer的运用

    序列化器的使用

    序列化器的使用分两个阶段:

      1.在客户端请求时:使用序列化器可以完成对数据的反序列化(就是前段往后端传递数据,反序列化之后保存数据)

      2.在服务器响应时,使用序列化器可以完成对数据的序列化(服务器取出数据,序列化之后往前段发送展示)

    序列化使用流程:

    基本使用:

      1.先查询出一个用户对象

    from models import user
    user = User.object.get(id=2)
    

      2.构造序列化器对象

    from user.serializers import UserSerializer
    user_ser = Userserializer(user)  #放入查询出的user对象
    

      3.获取序列化对象 通过data属性可以获取序列化后的数据

    上面查出来的user_ser是一个serializer对象,需要取出具体的数据传给前端,所有要用到 user_ser.data取出具体数据
    

      4.如果要被序列化的数据是包含多条数据的(也可以说被[ ]嵌套的,不管是多条还是单条),需要添加many=True参数

    user = models.User.objects.all()
    user_ser =  Userserialzier(user,many=True)
    

    反序列化使用流程:

    数据验证:

    1.使用序列化器进行反序列化时,需要对数据进行验证后,才能获取验证成功的数据或保存成模型类对象。

    2.在获取反序列化的数据前,必须调用is_valid()方法进行验证,验证成功返回True,否则返回False

    3.验证失败,可以通过序列化对象的errors属性获取错误信息,返回字典,包含了字段和字段的错误。

    4.验证通过,可以通过序列化器对象的validated_data属性获取数据

    保存数据:

    使用create()和save()方法

    配置层:settings.py

    # 注册rest_framework,以及其它settings配置
    INSTALLED_APPS = [
        # ...
        'rest_framework',
    ]
    

    **media资源路径设置 **(设置好后把图片放在这个文件夹中,通过链接能访问到图片)

    1.先在根目录设置一个media文件夹

    2.配置settings.py,加上下面的

    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    

    3.在urls.py路由设置

    from django.views.static import serve
    from django.conf import settings
    
    urlpatterns = [   
        url(r'^media/(?P<path>.*)', serve, {'document_root': settings.MEDIA_ROOT}),
    ]
    

    代码示例序列化和反序列化在Serialzier组件中使用

    序列化使用(展示给前台的数据)

    模型层:models.py

    class User(models.Model):
        SEX_CHOICES = [
            [0,'男'],
            [1,'女'],
        ]
    
        name = models.CharField(max_length=64)
        age = models.IntegerField(default=0)
        height = models.DecimalField(max_digits=5, decimal_place=2)
        pwd = models.CharField(max_length=32)
        phone = models.CharField(max_length=11,null=True,default=None)
        sex = models.IntegerField(choices=SEX_CHOICES,default=0)
        icon = models.ImageField(upload_to='icon',default='icon/default.jpg')
    
        class Meta:
            db_table='old_boy_user'
            verbose_name='用户'
            verbose_name_plural=verbose_name
    
        def __str__(self):
            return self.name
    
    

    序列化层:api/serializers.py (api应用下创建serializers.py文件)

    1)设置需要返回给前台数据样式 那些model类有对应的 字段,不需要返回的就不用设置了
    2)设置方法字段,字段名可以随意,字段值由 get_字段名 提供,来完成一些需要处理在返回的数据,类似于forms组件
    
    

    为这个模型类提供一个序列化器,可以定义如下,在自定义.py文件下:

    # 序列化组件 - 为每一个model类通过一套序列化工具类
    # 序列化组件的工作方式与django froms组件非常相似
    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)
        
        # sex = serializers.IntegerField() 选择类型的字段序列化出来的结果是数字,不是真正的值,所以这个时候要采用自定义序列化字段,通过自定义字段来接收原本数字的对应值,如下:
        # 自定义序列化字段,序列化的属性值由方法来提供,
        #   方法的名字:固定为 get_属性名,
        #   方法的参数:序列化对象,序列化的model对象    
        #   强烈建议自定义序列化字段名不要与model已有的属性名重名
    	
        # 自定义序列化属性,属性名随意,但由固定的方法提供
        gender = serializers.SerializerMethodField()
        def get_gender(self, obj):
            # print('>>>>>>', type(self))
            # print('>>>>>>', type(obj))
            #返回值就是自定义序列化属性的值
            # choice类型的解释型值 get_字段_display() 来访问
            return obj.get_sex_display()
        
        icon = serializers.SerializerMethodField()
        def get_icon(self, obj):
            # settings.MEDIA_URL: 自己配置的 /media/,给后面高级序列化与视图类准备的
            # obj.icon不能直接作为数据返回,因为内容虽然是字符串,但是类型是ImageFieldFile类型
            return '%s%s%s' % (r'http://127.0.0.1:8000', settings.MEDIA_URL, str(obj.icon))
    
    
    

    视图层:views.py

    视图层书写的三个步骤
    1)从数据库中将要序列化给前台的model对象,或是多个model对象查询出来
        user_obj = models.User.objects.get(pk=pk) 或者
        user_obj_list = models.User.objects.all()
    2)将对象交给序列化处理,产生序列化对象,如果序列化的数据是由[]嵌套,一定要设置many=True
        user_ser = serializers.UserSerializer(user_obj) 或者
        user_ser = serializers.UserSerializer(user_obj_list, many=True)
    3)序列化 对象.data 就是可以返回给前台的序列化数据
        return Response({
            'status': 0,
            'msg': 0,
            'results': user_ser.data
        })
    
    
    class User(APIView):
        def get(self, request, *args, **kwargs):
            pk = kwargs.get('pk')
            if pk:  #单查
                try:
                    # 用户对象不能直接作为数据返回给前台
                    user_obj = models.User.objects.get(pk=pk)
                    # 序列化一下用户对象
                    user_ser = serializers.UserSerializer(user_obj)
                    return Response({
                        'status': 0,
                        'msg': 'ok',
                        'results': user_ser.data   #如果你在序列化的时候没有.data,那么在传给前端的时候必须要.data
                    })
                except:
                    return Response({
                        'status': 2,
                        'msg': '用户不存在',
                    })
            else:  #群查
                # 用户对象列表(queryset)不能直接作为数据返回给前台
                user_obj_list = models.User.objects.all()
                # 序列化一下用户对象
                user_ser_data = serializers.UserSerializer(user_obj_list, many=True).data
                return Response({
                    'status': 0,
                    'msg': 0,
                    'results': user_ser_data
                })
    
    

    反序列化使用 (把数据存入数据库)

    反序列层:api/serializers.py

    1)设置必填与选填序列化字段,设置校验规则
    2)为需要额外校验的字段提供局部钩子函数,如果该字段不入库,且不参与全局钩子校验,可以将值取出校验 pop
    3)为有联合关系的字段们提供全局钩子函数,如果某些字段不入库,可以将值取出校验
    4)必须重写create方法,完成校验通过的数据入库工作,得到新增的对象
    
    
    from . import models
     	# 1) 哪些字段必须反序列化
        # 2) 字段都有哪些安全校验
        # 3) 哪些字段需要额外提供校验  钩子函数
        # 4) 哪些字段间存在联合校验
        # 注:反序列化字段都是用来入库的,不会出现自定义方法属性,会出现可以设置校验规则的自定义属性(re_pwd)
    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_aaa(self, value):
            if 'g' in value.lower():
                raise serializers.ValidationError('名字中不能有g')
            return value
    
        # 全局钩子:validate(self, 所有校验的数据字典)
        # 规则:成功返回attrs,失败抛异常
        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重写,完成入库
        def create(self, validated_data):
            return models.User.objects.create(**validated_data)
    
    
    • 视图层:views.py
    1)book_ser = serializers.UserDeserializer(data=request_data)  # 反序列化数据必须赋值data,结果就是得到一个serializer对象
    2)book_ser.is_valid()  # 把数据放到自定义serializer中校验,数据校验成功返回True,失败返回False
    3)不通过返回 book_ser.errors 给前台,通过 book_ser.save() 得到新增的对象,再正常返回
    
    
    class User(APIView):
        # 只考虑单增
        def post(self, request, *args, **kwargs):
            # 请求数据
            request_data = request.data
            # 数据是否合法(增加对象需要一个字典数据)
            if not isinstance(request_data, dict) or request_data == {}:
                return Response({
                    'status': 1,
                    'msg': '数据有误',
                })
            # 数据类型合法,但数据内容不一定合法,需要校验数据,校验(参与反序列化)的数据需要赋值给data
            book_ser = serializers.UserDeserializer(data=request_data)
    
            # 序列化对象调用is_valid()完成校验,校验失败的失败信息都会被存储在 序列化对象.errors
            if book_ser.is_valid():
                # 校验通过,完成新增
                book_obj = book_ser.save()
                return Response({
                    'status': 0,
                    'msg': 'ok',
                    'results': serializers.UserSerializer(book_obj).data
                })
            else:
                # 校验失败
                return Response({
                    'status': 1,
                    'msg': book_ser.errors,
                })
    
    

    序列化 ModelSerializer 模型类序列化器

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

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

    2.包含默认的create()和update()的实现

    3.基于模型类自动为Serializer生成validators,比如unique_together

    序列化层:api/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 = models.User  #选择哪个表
            
            #选择需要序列化的字段,前端只显示这些字段(指明为模型类的哪些字段生成)
            fields = ['name', 'age', 'height', 'gender', 'pwd', 're_pwd']
            extra_kwargs = {
                'name': {
                    'required': True,
                    'min_length': 3,
                    'error_messages': {
                        'min_length': '太短'
                    }
                },
                'age': {
                    'required': True,  # 数据库有默认值或可以为空字段,required默认为False
                    'min_value': 0
                },
                'pwd': {
                    'required': True,
                    'write_only': True,  # 只参与反序列化
                },
                'gender': {
                    'read_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已经帮我们重写了入库方法
    
    

    模型层:models.py

     # 自定义插拔序列化字段:替换了在Serializer类中自定义的序列化字段(SerializerMethodField)
        # 自定义插拔序列化字段一定不参与反序列化过程
        @property
        def gender(self):
            return self.get_sex_display()
    
    

    视图层:views.py

     # 单增
        def post(self, request, *args, **kwargs):
            # 从请求对象中拿到前台的数据
            # 校验前台数据是否合法
            # 反序列化成后台Model对象与数据库交互
            request_data = request.data
    
            # 反序列化目的:封装数据的校验过程,以及数据库交互的过程
            user_ser = serializers.UserDeserializer(data=request_data)
            # 调用反序列化的校验规则:系统规则,自定义规则(局部钩子,全局钩子)
            result = user_ser.is_valid()
    
            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)
    
    

    序列化、反序列化总结

    """ 序列化
    一、视图类的三步操作
    1)ORM操作数据库拿到资源数据
    2)格式化(序列化)成能返回给前台的数据
    3)返回格式化后的数据
    
    二、视图类的序列化操作
    1)直接将要序列化的数据传给序列化类
    2)要序列化的数据如果是单个对象,序列化的参数many为False,数据如果是多个对象(list,queryset)序列化的参数many为True
    
    三、序列化类
    1)model了中要反馈给前台的字段,在序列化类中要进行声明,属性名必须就是model的字段名,且Field类型也要保持一致(不需要明确规则)
    2)model了中不需要反馈给前台的字段,在序列化类中不需要声明(省略)
    3)自定义序列化字段用 SerializerMethodField() 作为字段类型,该字段的值来源于 get_自定义字段名(self, obj) 方法的返回值
    """
    
    
    """ 反序列化
    一、视图类的三步操作
    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 失败抛出校验错误的异常
    """
    
    

    单表查询总结

    """ 单表序列化总结
    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
    """
    
    
  • 相关阅读:
    【SQL】语句/函数汇总
    【SVN】提交报错:×××文件is not under version control
    【AnjularJS系列1】样式相关的指令
    【Javescript】DOM(文档对象模型)
    【HTML】框架集(Framesets)
    【HTML】<!DOCTYPE html>作用
    vue2.0移动端自定义性别选择提示框
    微信小程序踩坑记
    网页里如何使用js禁用F12事件
    网页里如何使用js屏蔽鼠标右击事件
  • 原文地址:https://www.cnblogs.com/chmily/p/11935071.html
Copyright © 2020-2023  润新知