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方法

posted @ 2019-12-25 23:29  fwzzz  阅读(494)  评论(0编辑  收藏  举报