zoukankan      html  css  js  c++  java
  • 1225 drf序列化ModelSerializer序列化与反序列化

    Serializer类
        底层序列化类	了解类
        重点:单表序列化
    
    ModelSerializer
        模型序列化类  核心类
        重点: 多表序列化
    
    ListSerializer类
    	群操作序列化	辅助类
        重点:辅助完成单表多表群增群改操作
    

    drf序列化

    1. django项目的设置

    settings中配置
    1.注册app以及rest_framework
        INSTALLED_APPS = [
            'django.contrib.admin',
            'django.contrib.auth',
            'django.contrib.contenttypes',
            'django.contrib.sessions',
            'django.contrib.messages',
            'django.contrib.staticfiles',
            
            # drf中一定要注册才能使用
            'rest_framework',
            
            # 注册app
            'api',
        ]
        
        
    2.使用mysql数据库
        DATABASES = {
            'default': {
                'ENGINE': 'django.db.backends.mysql',
                'NAME': 'day72',
                'USER':'root',
                'PASSWORD':'',
            }
        }
        import pymysql
        pymysql.install_as_MySQLdb()
        
        
    # 国际化配置
        LANGUAGE_CODE = 'zh-hans'
        TIME_ZONE = 'Asia/Shanghai'
        USE_I18N = True
        USE_L10N = True
        USE_TZ = False
        
        		
    # 静态文件配置
    	STATIC_URL = '/static/'
    	
    # 媒体文件配置
        MEDIA_URL = '/media/'
        MEDIA_ROOT = os.path.join(BASE_DIR,'media')
    

    models.py配置

    from django.db import models
    
    # Create your models here.
    from django.db import models
    
    class User(models.Model):
        # 配置sex的选项
        SEX_CHOICES = (
            (0,'女'),
            (1,'男')
        )
        # verbose_name定义了admin显示表的字段名称,blank则可以在admin中可以空提交
        username = models.CharField(max_length=64,verbose_name='用户名',blank=True)
        password = models.CharField(max_length=64,verbose_name='密码')
        sex = models.IntegerField(choices=SEX_CHOICES,default=0,verbose_name='性别')
        icon = models.ImageField(upload_to='img',default='img/default.jpg',verbose_name='头像')
        # 开发中,数据不会直接删除,通过字段控制
        is_delete = models.BooleanField(default=False,verbose_name='是否注销')
        # 数据库数据入库,一般都会记录该数据第一次入库时间,有时候还会记录最后一次更新事假
        created_time = models.DateTimeField(auto_now_add=True,verbose_name='创建时间')
    
    
        # 配置类,给所属的类提供配置信息
        class Meta:
            db_table = 'old_boy_user'
            verbose_name_plural = '用户表'
    
        # 不要在这里进行联表操作,比如admin页面会崩溃
        def __str__(self):
            return self.username
    

    APP中的admin.py设置

    from django.contrib import admin
    
    # Register your models here.
    from . import models
    admin.site.register(models.User)
    

    项目url.py

    from django.conf.urls import url,include
    from django.contrib import admin
    
    # 设置django的media配置文件
    from django.views.static import serve
    from django.conf import settings
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^api/',include('api.urls')),
        url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT})
    ]
    
    

    三流(补充)

    import sys
    
    标准输出流
    sys.stdout.write(123)	# 会在控制台上打印123(不自动换行)
    
    标准输入流
    res = sys.stdin.readline()	# 读取控制台上的数据
    print(res)
    
    标准错误流
    sys.stderr.write('123/n')	# 出现红色的打印信息
    sys.stderr.write('123/n')
    
    流的打印是异步的,但相同流之间的打印是同步的
    

    2. 序列化

    1. 自定义序列化过程

    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from django.conf import settings
    
    from . import models
    class UserV1APIView(APIView):
        # 单查群查
        def get(self,request,*args,**kwargs):
            pk = kwargs.get('pk')
            if pk:
                user_dic = models.User.objects.filter(is_delete=False,pk=pk).values('username','sex','icon').first()
                if not user_dic:
                    return Response({
                        'status': 1,
                        'msg': 'pk error',
                    },status=400)
                user_dic['icon'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,user_dic.get('icon'))
                return Response({
                    'status':0,
                    'msg':'ok',
                    'results':user_dic
                })
            else:
                user_query = models.User.objects.filter(is_delete=False).values('username','sex','icon')
                for user_dic in user_query:
                    user_dic['icon'] = '%s%s%s' % (settings.BASE_URL,settings.MEDIA_URL,user_dic.get('icon'))
                user_list = list(user_query)
                return Response({
                    'status':0,
                    'msg':'ok',
                    'results':user_list
                })
    

    3. Serializer类

    3.1 序列化过程

    视图类序列化过程
        1. orm操作得到数据
        2. 将数据序列化成可以返回给前台的数据
        3. 返回数据给前台
    

    导入rest_framework的类serializers

    • 字段名与字段类型要与处理的model类相对应

    • 不提供的字段,就不参与序列化给前台

    • 可以自定义序列化字段,采用方法序列化

      方法固定两个参数,第二个参数就是参与序列化的model对象
      
      严重不建议自定义字段名与数据库字段名重名,由get_'自定义字段名'方法的返回值提供字段值
      
      
    序列化过程
    
    --------------------------------------------------------
    
    from . import serializers
    class UserV2APIView(APIView):
        # 单查群查
        def get(self,request,*args,**kwargs):
            pk = kwargs.get('pk')
            if pk:
                # 获取数据对象
                user_obj = models.User.objects.filter(is_delete=False,pk=pk).first()
                if not user_obj:
                    return Response({
                        'status': 1,
                        'msg': 'pk error',
                    },status=400)
                # 交于视图类的序列化统一处理
                user_ser = serializers.UserSerializers(user_obj,many=False)  # many 默认为false
                # 获取序列化返回的数据
                user_obj_data = user_ser.data
                return Response({
                    'status':0,
                    'msg':'ok',
                    'results':user_obj_data
                })
            else:
                # 将对象对外提供的字段,以及整个序列化过程封装,形成序列化类
                user_query = models.User.objects.filter(is_delete=False).all()
                user_ser = serializers.UserSerializers(user_query,many=True)
                # 将序列化后的所有数据返回出来,放在data中
                user_list = user_ser.data
    
                return Response({
                    'status':0,
                    'msg':'ok',
                    'results':user_list
                })
                
    --------------------------------------------------------
    
    
    from django.conf import settings
    # 导入rest_framework的类serializers
    from rest_framework import serializers
    class UserSerializers(serializers.Serializer):
        # 1.字段名与字段类型要与处理的model类相对应
        username = serializers.CharField()
        # 2.不提供的字段, 就不参与序列化给前台
        # sex = serializers.IntegerField()
        # 3.可以自定义序列化字段, 采用方法序列化
        gender = serializers.SerializerMethodField()
            # 这里的obj就是传入的user对象
        def get_gender(self,obj):
            return obj.get_sex_display()
        icon = serializers.SerializerMethodField()
        # 在高级序列化与高级视图类中,drf默认帮我们处理图片等子资源的
        def get_icon(self,obj):
            return '%s%s%s' % (settings.BASE_URL, settings.MEDIA_URL, obj.icon)
    
    

    序列化总结

    • 设置序列化字段,字段名与字段类型要与处理的model类属性名对应(只参与序列化的类型不需要设置条件)
    • model类中有的字段,但在序列化中没有对应字段,该类字段不参与序列化
    • 自定义序列化字段(方法一),字段类型为SerializerMethodField(),值由 get_自定义字段名(self, model_obj) 方法提供,一般值都与参与序列化的model对象(model_obj)有关

    3.2 反序列化

    视图类反序列化过程
    	1. 从请求对象中获取前台提交的数据
    	2. 交给序列化类完成反序列化(数据的校验) 重要
    	3. 借助序列化类完成数据入库
    	4. 反馈给前台处理结果
    
    
    # 单增
        def post(self,request,*args,**kwargs):
            # 用户输入的数据都在 request.data 中
            request_data = request.data
            # 反序列化必须使用data来指定
            user_ser = serializers.UserDeSerializers(data=request_data)
            # is_valid判断反序列化校验结果
            if user_ser.is_valid():
                # 入库,获取一个User对象
                user_obj = user_ser.save()
                return Response({
                    'status':0,
                    'msg':'ok',
                    # 这里利用序列化,将user_obj重新序列化返回data信息给前台
                    'results':serializers.UserSerializers(user_obj).data
                })
            else:
                return Response({
                    'status':0,
                    'msg':'ok',
                    # 反序列化错误的信息都在.errors中(做了国际化)
                    'results':user_ser.errors
                })
    
    
    -------------------------------------------------------
    
    from . import models
    # 反序列化的类
    class UserDeSerializers(serializers.Serializer):
        # 系统校验字段(用于校验的表的属性)
    
        # 不写,不参与反序列化,写就一定参与反序列化(但可以设置required=False取消必须)
        # 反序列化的自定义校验信息
        username = serializers.CharField(min_length=3,max_length=8,error_messages={
            'min_length':'短',
            'max_length':'长'
        })
        # 不需要定义报错信息也可以,国际化会自动提示
        password = serializers.CharField(min_length=3,max_length=8)
        # required = False控制字段可以不填写
        sex = serializers.BooleanField(required=False)
    
        # 自定义校验字段: 从设置语法与系统字段没有区别,但是这些字段不能参加入库操作,需要在全局钩子中将其取出
        re_password = serializers.CharField(min_length=3, max_length=8)
    
    
        # 局部钩子
        #     方法名就是validate_校验的字段名(self,校验的字段数据)
        #     校验规则:成功之后返回values,失败抛出校验失败信息
        def validate_username(self,values):
            if 'g' in values:
                # 报错信息的添加在serializers.ValidationError中添加即可
                raise serializers.ValidationError('名字中不能有g')
            return values
    
        # 全局钩子
        #     方法名就是validate(self,所有的校验数据)
        #     校验规则:成功之后返回attrs,失败抛出校验失败信息
        def validate(self, attrs):
            password = attrs.get('password')
            re_password = attrs.pop('re_password')
            if password != re_password:
                raise serializers.ValidationError({'re_password':'两次密码不一致'})
            return attrs
    
    
        # 在视图类中调用序列化类的save方法完成入库,serializers类能做的:增入库走create方法,改入库走update方法
        # 但serializers没有提供两个方法的实现体
        def create(self, validated_data):
            return models.User.objects.create(**validated_data)
    
        # instance要被修改的对象,validated_data代表校验后用来改instance的数据
        def update(self, instance: models.User, validated_data):
            # 用户名不能被修改
            validated_data.pop('username')
            models.User.objects.filter(pk=instance.id).update(**validated_data)
            return instance
    
    

    反序列化总结

    • 系统校验字段与自定义校验字段定义没有区别:字段 = serializers.字段类型(条件)

    • 自定义校验字段是不能直接入库的,需要设置入库规则,或将其移除不入库(这类字段就是参与全局校验用的)

    • 所有字段都可以设置对应局部钩子进行校验

      钩子方法
      	validate_字段名(self, 字段值value)
      	
      规则:
      	成功直接返回value,失败抛出校验失败信息ValidationError('错误信息')
      
      
    • 一个序列化类存在一个全局钩子可以对所有字段进行全局校验

      钩子方法
      	 validate(self, 所有字段值字典attrs)
      	 
      规则:
      	成功直接返回attrs,失败抛出校验失败信息ValidationError({'异常字段', '错误信息'})
      
      
    • 重写create方法实现增入库,返回入库成功的对象

    • 重写update方法实现改入库,返回入库成功的对象

    4. ModelSerializer序列化

    #  定义类并继承serializers.ModelSerializer
    class 自定义名称(serializers.ModelSerializer):
        class Meta:
            model=对应的模型类
            fields=('参与序列化和反序列的字段1','参与序列化和反序列的字段2')
            extra_kwargs ={
                参与序列化和反序列的字段1:{
                    'required': True,  #必须填写的字段
                     # 约束条件
                     'min_length': 3,
    				# 报错信息
                    'error_messages': {
                        'min_length': '太短'
                    },
                    {
                参与序列化和反序列的字段2:{
                     'write_only': True 	#只写, 反序列化
                }
                参与序列化和反序列的字段3:{
                     'read_only': True 		#只读, 序列化
                }
                }
            }
    
    

    使用代码

        # 单增
        def post(self,request,*args,**kwargs):
            # 反序列直接将前台的数据传给类
            user_ser = serializers.UserModelSerializers(data=request.data)
            # is_valid判断反序列化校验结果
            if user_ser.is_valid():
                # 入库,获取一个User对象
                user_obj = user_ser.save()
                return Response({
                    'status':0,
                    'msg':'ok',
                    # 这里利用序列化,将user_obj重新序列化返回data信息给前台
                    'results':serializers.UserModelSerializers(user_obj).data
                })
            else:
                return Response({
                    'status':0,
                    'msg':'ok',
                    # 反序列化错误的信息都在.errors中(做了国际化)
                    'results':user_ser.errors
                })
    
    --------------------------------------------------------
    
    # 核心:单表序列化与反序列化操作
    class UserModelSerializers(serializers.ModelSerializer):
    
    # 1. 序列化
    
        # 第一种自定义序列化字段:该字段必须在fields中设置
            # gender = serializers.SerializerMethodField()
            # def get_gender(self,obj):
            #     return obj.get_sex_display()
        # 第二种,在models中定义 @property 方法
        # @property
        # def gender(self):
        #     return self.get_sex_display()
    
        # 自定义反序列化字段同Serializer类,且规则只能在此声明中设置,或在钩子中设置,在extra_kwargs中设置无效
        # 必须设置write_only
        re_password = serializers.CharField(min_length=3,max_length=6)
    
        # 系统字段
        class Meta:
            # 必须先绑定类
            model = models.User
            # fields采用"插拔式设计" 设置了参与序列化与反序列化的字段
            fields = ('username','gender','icon','password','sex','re_password')
    # 2.反序列化
    #     如何将序列化与反序列化区分开
    #     如何对反序列化字段进行校验
            extra_kwargs = {
                'username':{   # 系统字段,不设置only,默认都参加
                    # 自定义校验信息
                    'min_length':3,
                    'max_length':10,
                    'error_messages':{
                        'min_length': '短',
                        'max_length': '长',
                    }
                },
                'gender':{ # 自定义的序列化字段就是read_only,且不能修改,但可以省略
                    # 只参与序列化 'read_only':True
                    'read_only':True
                },
                'password':{
                    # 只参与反序列化 'write_only':True
                    'write_only':True
                },
                # 像sex有默认值的字段,为选填字段,'required':True将其变为必填字段
                'sex':{
                    'write_only': True,
                    'required':True
                }
            }
    
    
        # 局部钩子与全局钩子是与Meta同缩进的
    
        # 局部钩子
        def validate_username(self,values):
            if 'g' in values:
                raise serializers.ValidationError('名字中不能有g')
            return values
        # 全局钩子
        def validate(self, attrs):
            password = attrs.get('password')
            re_password = attrs.pop('re_password')
            if password != re_password:
                raise serializers.ValidationError({'re_password':'两次密码不一致'})
            return attrs
    
    
        # create与update方法不要再重写,ModelSerializers类已经提供,且支持所有关系下的联表操作
    

    序列化与反序列化总结

    • 序列化类继承ModelSerializer,所以需要在配置类Meta中进行配置

      • model配置:绑定序列化相关的Model表

      • fields配置:采用 插拔式 设置所有参与序列化与反序列化字段

      • extra_kwargs配置:

        划分系统字段为三种:
        	只读(read_only)、只写(write_only)、可读可写(不设置)
        	
        字段是否必须:
        	'required':True将其变为必填字段
        	
        选填字段:
        	在extra_kwargs进行配置,但不设置required,且有默认值
        
    • 自定义序列化字段:

      * 第一种(不提倡):
          # 该字段必须在fields中设置
              gender = serializers.SerializerMethodField()
              def get_gender(self,obj):
                  return obj.get_sex_display()
      
      * 第二种(提倡):
      	# 在模型类中用@property来实现,可插拔
          @property
          def gender(self):
              return self.get_sex_display()
      
    • 自定义反序列化字段:

      同Serializer类,且规则只能在此声明中设置,或是在钩子中设置,在extra_kwargs中对其设置的无效
      
      自定义反序列化字段与系统字段,设置规则一样,所以必须设置 write_only
      
    • 局部钩子,全局钩子同Serializer类

    • 不需要重写create和update方法

  • 相关阅读:
    【NOIP模拟赛】正方形大阵
    【优化王牌】二分查找
    【Ah20160703】咏叹 By C_SUNSHINE
    【NOIP模拟赛】lover——心上人
    【小奇模拟赛】小奇挖矿2
    【NOIP模拟赛】工资
    关于博客装修的说明
    【快速处理】分块算法
    【集训】 考试笔记
    【HDNOIP】HD201404最短路径
  • 原文地址:https://www.cnblogs.com/fwzzz/p/12099673.html
Copyright © 2011-2022 走看看