zoukankan      html  css  js  c++  java
  • 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
    """
    
    
  • 相关阅读:
    VisualSVN-Server windows 版安装时报错 "Service 'VisualSVN Server' failed to start. Please check VisualSVN Server log in Event Viewer for more details."
    Pytest 单元测试框架之初始化和清除环境
    Pytest 单元测试框架入门
    Python(email 邮件收发)
    Python(minidom 模块)
    Python(csv 模块)
    禅道简介
    2020年最好的WooCommerce主题
    Shopify网上开店教程(2020版)
    WooCommerce VS Magento 2020:哪个跨境电商自建站软件更好?
  • 原文地址:https://www.cnblogs.com/chmily/p/11935071.html
Copyright © 2011-2022 走看看