Django Rest_framework 6(序列化与反序列化)

一、Django RestFrameWork 简介/安装

作用:提高RestAPI接口开发的效率
关键功能:
	序列化器:序列化和反序列化
	类视图,MiXin扩展类:简化视图代码的编写
安装: pip install djangorestframework
        INSTALLED_APPS = [
            ...
            'rest_framework', # 添加
        ]

二、DRF框架-RestAPI接口的核心工作

序列化:将模型对象转换为字典或者json的过程,叫做序列化的过程。
反序列化:将客户端传递的数据保存转化到模型对象的过程,叫做反序列化的过程。

核心:
1. 将数据库数据序列化为前端所需要的格式,并返回;
2. 将前端发送的数据反序列化为模型类对象,并保存到数据库中。

三、序列化与反序列化

1.序列化器Serializer-功能&知识点说明
DRF中的serializer就类似于Djano中的Form,只不过Form是针对模板的,而serializer是针对json,而且非常强大

功能:进行数据的序列化和反序列化
使用:首先定义序列化器类

序列化功能:将对象转换字典。
	1.序列化单个对象(many=False)
	2.序列化多个对象(many=True)
	3.关联对象的嵌套序列化

反序列化功能:
	数据校验:
		1.基本验证
		2.补充验证
	数据保存
		1.数据新增create
		2.数据更新update
2.序列化器Serializer-定义&基本使用
定义模型类:
	class 模型类(modles.Model):
		模型字段 = models.字段类型(选项参数)

定义序列化器类:
	from rest_framework import serializers
	class 序列化器类(serializers.Serializer):
    	序列化器字段= serializers.字段类型(选项参数)
        
序列化器类(instance=None,data={},**kwargs)
	1.进行序列化操作,将对象传递给instance
    2.进行反序列化操作,将数据传递给data
        如果创建序列化器对象的时候,没有传递instance实例,create()被调用,
        如果传递了instance实例,则调用save()方法的时候,update()被调用。
        
    serializer = BookSerializer(data=data)   # 没有传递instance实例,新建数据
	serializer = BookSerializer(book,data=data)   # 传进了instance参数,表示更新数据库

四、Serializer

1.实例
class User(object):
    """用户类"""
    def __init__(self, name, age):
        self.name = name
        self.age = age


class UserSerializer(serializers.Serializer):
    name = serializers.CharField()
    age = serializers.IntegerField()
    
    
 序列化:
#     user = User(name="Monkey", age=18)
#     res = UserSerializer(user) #序列化多个对象,需要添加many=True
#     dict = res.data

反序列化:
# 假如现在客户端给服务器传递了两个参数:那name,age,利用这两个数据创建一个用户的对象,但是需要先进行数据校验
    req_data = {
        'name':"Moneky",
        # "age":24
    }
    # 反序列化-数据校验
    serializer = UserSerializer(data=req_data)
    res = serializer.is_valid()
    print(res)

   
    print(serializer.errors)   # 获取校验出错的信息  
    print(serializer.validated_data)    # 获取校验之后的数据
    serializer.save()保存数据(调用序列化类的create方法)

2.字段类型&选项参数说明
	class 模型类(modles.Model):
		模型字段 = models.字段类型(选项参数)
		
在定义序列化器类的字段时,write_only和read_only默认值为False,说明这个字段既在序列化时使用,也在反序列化时使用。
通用选项参数:
	write_only: 设置为True,该字段只在序列化时使用,反序列化操作时不使用
	read_only: 设置为True,该字段只在序列化时使用,反序列化时不使用
	default:设置序列化和反序列化时所使用的默认值
	requird:默认值是True,指明在进行反序化时此字段是否必须传入
	allow_null	表明该字段是否允许传入None,默认False
	validators	该字段使用的验证器,
	eg:(验证是否唯一)validators=
	[UniqueValidator(queryset=UserProfile.objects.all(), message='用户已存在')]
	error_messages	包含错误编号与错误信息的字典
	label	用于HTML展示API页面时,显示的字段名称
	help_text	用于HTML展示API页面时,显示的字段帮助提示信息
	style	控制浏览器如何渲染此字段,例如 'input_type' 和 'base_template'

3.主从表数据关联查询

PrimaryKeyRelatedField
StringRelatedField
SlugRelatedField
HyperlinkedRelatedField
HyperlinkedIdentityField
展示主表的详细信息

4.添加数据(create)

- 我们,想要添加数据,就需要在序列化器类中定义一个create()方法。
在这里,我们需要返回添加的数据给前端,因为我们定义的API是遵守RESTful设计风格的。

- 当我们创建序列化对象时,只传递data数据,就表示我们需要向数据库里添加数据。
所以,当序列化器对象调用save()方法时,会自动调用序列化器类中的create()方法。	
	
例如:

def create(self, validated_data):
	'''
	序列化器进行新增数据的方法
	:param validated_data: 通过验证的字典数据
	:return:根据RESTful设计方式,需要将添加的数据返回
	'''

	return BookInfo.objects.create(**validated_data)

5.更新数据(update)

我们,想要修改数据时,需要在序列化器类中定义一个update()方法。	
例如:

def update(self, instance, validated_data):
	'''
	序列化器进行修改数据的方法
	:param instance: 需要修改的模型对象
	:param validated_data: 前端传递的字典数据
	:return: 根据RESTful设计方式,需要将修改的数据返回
	'''

	# 新值覆盖旧值
	instance.字段名 = validated_data.get(字段名)
	instance.title = validated_data.get('title')
	instance.pub_date = validated_data.get('pub_date')
	instance.read = validated_data.get('read')
	instance.comment = validated_data.get('comment')
	instance.save()

	return instance

6.添加与更新实例

#在serializer中拿到user对象:user = self.context['request'].user
#用户进行加入购物车操作时,不是直接在数据库表中添加,需要判断该商品购物车中是否已存在
重写create,update方法
class ShopCartSerializer(serializers.Serializer):
    user = serializers.HiddenField(default=CurrentUserDefault())
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())
    nums = serializers.IntegerField(required=True, min_value=1, error_messages={
        'required': '商品数量必须添加',
        'min_value': '商品数量不能少于1'
    })

    def create(self, validated_data):
    	#在serializer中拿到user对象:user = self.context['request'].user
        # goods: this.productId, // 商品id   nums: this.buyNum, // 购买数量
        goods = validated_data['goods']
        nums = validated_data['nums']
        user = self.context['request'].user

        # 进行数据库的查询
        shopcart = ShoppingCart.objects.filter(user=user, goods=goods)
        if shopcart.exists():
            # 原来在购物车中存在此商品
            cart = shopcart.first()
            cart.nums += nums
            cart.save()
        else:
            # 购物车中此用户没有添加过此商品
            cart = ShoppingCart.objects.create(user=user, goods=goods, nums=nums)
        return cart

    def update(self, instance, validated_data):
        # instance shopcart对象
        instance.nums = validated_data['nums']
        instance.save()
        return instance
7.补充验证(3种方法)
a.指定特定字段选项参数validators来指明补充验证函数
(验证是否唯一)
	validators=
	[UniqueValidator(queryset=UserProfile.objects.all(), message='用户已存在')]
b. 在序列化器类中定义特定的方法validate_来针对特定字段进行补充验证
class SmsSerializer(serializers.Serializer):
    mobile = serializers.CharField(max_length=11)

    def validate_mobile(self, mobile):
        if UserProfile.objects.filter(mobile=mobile).exists():
            raise serializers.ValidationError('此手机号码已注册')
        if not re.match(REGEX, mobile):
            raise serializers.ValidationError('手机号码格式错误')
        return mobile
        
    def validate_code(self, code):
    	#init_data 指的是最原始的没有经过验证的数据
    	#取前端传递过来的参数用self.initial['username']
        verifyCodes = VerifyCode.objects.filter(mobile=self.initial_data['username']).order_by('-send_time')
c. 定义validate方法进行补充验证:来补充对所有字段进行扩展验证的逻辑
    def validate(self, attrs):
        #在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:
        # request、format、view,这三个数据对象可以在定义序列化器时使用
        mobile = self.context['view'].kwargs['mobile']  
        
    def validate(self, attrs):  # 全局验证    ['username','password','mobile']
    	'''
        对多个字段进行验证
        :param attrs: 前段传递的字典数据
        :return: 验证成功:返回attrs;验证失败:返回错误信息
        '''
        attrs['mobile'] = attrs['username']
        del attrs['code']
        return attrs

五、ModelSerializer

	是Serizalizer类的子类,在定义序列化器类时,如果序列化器类针对的是某个模型类,可以直接继承于ModelSerializer。
	ModelSerializer同Serializer很相似,只不过建立了序列化类和Model类的强联系,简化了代码,提高了代码的可重用性。
	
好处:
    - 基于模型类自动生成一系列字段
    - 基于模型类自动为Serializer生成validators,比如unique_together
    - 包含默认的create()和update()的实现
1.创建序列化器
class BookSerializer(serializers.ModelSerializer):
    # model 指明该序列化器处理的数据字段从模型类BookInfo参考生成
    # fields 指明该序列化器包含模型类中的哪些字段,'__all__'指明包含所有字段
   class Meta:
       model = BookInfo
       fields = '__all__' # 返回给前端的json中包含的字段
2.fields:使用 fields 来明确字段, __all__ 表名包含所有字段,也可以写明具体哪些字段 :
class Meta:
        model = HeroInfo
        fields = '__all__'
        fields = ('id', 'btitle', 'bpub_date')
3.exclude: 使用exclude可以明确排除掉哪些字段
 class Meta:
        model = HeroInfo
 		exclude = ('image',)
4.depth:但是我们可以使用depth来简单的生成嵌套表示,depth应该是整数,表明嵌套的层级数量
class Meta:
        model = HeroInfo
        fields = '__all__'
        depth = 1
5.extra_kwargs:在ModelSerializer序列化器中,我们可以通过在Meta类中,指定extra_kwargs属性的值来为指定的字段添加验证参数。
这里,我们需要注意的时extra_kwargs属性的值个格式是个字典。
class Meta:
        model = Classes
        fields = "__all__"
        extra_kwargs = {
             'bcomment':{
				'min_value':0,
				'max_value':99999
			}
        }
6.read_only_fields:可以通过read_only_fields指明只读字段,即仅用于序列化输出的字段
class BookSerializer2(serializers.ModelSerializer):
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
        read_only_fields = ('id', 'bread', 'bcomment')
7.联合唯一的验证
class Meta:
        model = UserFav
        validators = [
            UniqueTogetherValidator(
                queryset=UserFav.objects.all(),
                fields=('user', 'goods'),
                message="已经收藏"
            )
        ]

六、Serializer与ModelSerializer其他字段

1.serializerMethodField

在我们开发的时候,我么使用序列化器序列化返回的时候,返回的大多都是数据框中一个表中的字段,但是我们还想返回一些其他表(关联表)中的字段数据或者数据库中没有的字段怎么办,或者说根据字段数据(true flase)来返回别的数据,此时怎么办哪,drf框架已经帮我们想好了,他就是serializerMethodField

标准写法就是get_名字,instance表示的是此时你model中的对象,可以根据此对象来查询关联的数据库中字段的数据,
class MessageListSerializer(serializers.ModelSerializer):
    id = serializers.IntegerField(read_only=True)
    title = serializers.CharField(read_only=True)
    created_at = serializers.DateTimeField(read_only=True)
    is_read = serializers.SerializerMethodField()

    def get_is_read(self, obj):
    	#这里的obj是Serializer的Model经过查询后的结果集中的每个对象,也就是说,每查询到一个符合条件的纪录,该函数就会执行一次,向这个纪录中序列化这个函数字段
        # return '已读' if obj['is_read'] else '未读'

        return '已读' if obj.is_read else '未读'

    class Meta:
        model = Message
        fields = ('id', 'title', 'created_at', 'is_read')`

2.HiddleField隐藏字段

不依靠输入,而需要设置默认的值,不需要用户自己post数据过来,也不会显式返回给用户,最常用的就是user!!
# 获取当前用户,并且隐藏了该字段,不会序列化返回给前端
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    
原理:源码:提取request中的user,前端返回的token中会带上user信息
class CurrentUserDefault(object):
    def set_context(self, serializer_field):
        self.user = serializer_field.context['request'].user

    def __call__(self):
        return self.user

    def __repr__(self):
        return unicode_to_repr('%s()' % self.__class__.__name__)

七、为什么DRF中有时候返回的json中图片是带域名的,有时候是不带域名的呢?

带域名的结果是在view中对模型类序列化的,DRF在序列化图片的时候 会检查上下文有没有request,如果有,就给图片加上域名,

比如说我们视图用的是apiview():

我们需要序列化数据的时候,加  context={"request":request}
在提供序列化器对象的时候,REST framework会向对象的context属性补充三个数据:request、format、view,
TestSerilaizer(instance=instance, context={"request":request})

在序列化器里调用序列化器
goods_json = GoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).data    #注意具体语法

你可能感兴趣的:(Django Rest_framework 6(序列化与反序列化))