作用:提高RestAPI接口开发的效率
关键功能:
序列化器:序列化和反序列化
类视图,MiXin扩展类:简化视图代码的编写
安装: pip install djangorestframework
INSTALLED_APPS = [
...
'rest_framework', # 添加
]
序列化:将模型对象转换为字典或者json的过程,叫做序列化的过程。
反序列化:将客户端传递的数据保存转化到模型对象的过程,叫做反序列化的过程。
核心:
1. 将数据库数据序列化为前端所需要的格式,并返回;
2. 将前端发送的数据反序列化为模型类对象,并保存到数据库中。
DRF中的serializer就类似于Djano中的Form,只不过Form是针对模板的,而serializer是针对json,而且非常强大
功能:进行数据的序列化和反序列化
使用:首先定义序列化器类
序列化功能:将对象转换字典。
1.序列化单个对象(many=False)
2.序列化多个对象(many=True)
3.关联对象的嵌套序列化
反序列化功能:
数据校验:
1.基本验证
2.补充验证
数据保存
1.数据新增create
2.数据更新update
定义模型类:
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参数,表示更新数据库
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方法)
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
validators
来指明补充验证函数(验证是否唯一)
validators=
[UniqueValidator(queryset=UserProfile.objects.all(), message='用户已存在')]
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')
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
是Serizalizer类的子类,在定义序列化器类时,如果序列化器类针对的是某个模型类,可以直接继承于ModelSerializer。
ModelSerializer同Serializer很相似,只不过建立了序列化类和Model类的强联系,简化了代码,提高了代码的可重用性。
好处:
- 基于模型类自动生成一系列字段
- 基于模型类自动为Serializer生成validators,比如unique_together
- 包含默认的create()和update()的实现
class BookSerializer(serializers.ModelSerializer):
# model 指明该序列化器处理的数据字段从模型类BookInfo参考生成
# fields 指明该序列化器包含模型类中的哪些字段,'__all__'指明包含所有字段
class Meta:
model = BookInfo
fields = '__all__' # 返回给前端的json中包含的字段
__all__
表名包含所有字段,也可以写明具体哪些字段 :class Meta:
model = HeroInfo
fields = '__all__'
fields = ('id', 'btitle', 'bpub_date')
class Meta:
model = HeroInfo
exclude = ('image',)
class Meta:
model = HeroInfo
fields = '__all__'
depth = 1
这里,我们需要注意的时extra_kwargs属性的值个格式是个字典。
class Meta:
model = Classes
fields = "__all__"
extra_kwargs = {
'bcomment':{
'min_value':0,
'max_value':99999
}
}
class BookSerializer2(serializers.ModelSerializer):
class Meta:
model = BookInfo
fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')
read_only_fields = ('id', 'bread', 'bcomment')
class Meta:
model = UserFav
validators = [
UniqueTogetherValidator(
queryset=UserFav.objects.all(),
fields=('user', 'goods'),
message="已经收藏"
)
]
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__)
带域名的结果是在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 #注意具体语法