Serializer及ModelSerializer的使用
1、 使用Serializer类
serializer的基础使用
DRF中的serializer就类似于Djano中的Form,只不过Form是针对模板的,而serializer是针对json,而且非常强大
- 以以下代码为例
class GoodsSerializer(serializers.ModelSerializer):# name = serializers.CharField(required=True,max_length=100)# click_num = serializers.IntegerField(default=0)# market_price = serializers.FloatField(default=0.0)# goods_cover = serializers.ImageField()# add_time = serializers.DateTimeField()class Meta:model = Goods# field = ('name','click_num','add_time') # 返回给前端的json中包含的字段field = "__all__" # 包含所有字段def create(self, validated_data):"""Create and return a new `Good` instance, given the validated data."""return Goods.objects.create(**validated_data)
序列化单个字段
name = serializers.CharField(required=True,max_length=100)
HiddleField隐藏字段
# 获取当前用户,并且隐藏了该字段,不会序列化返回给前端
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'].userdef __call__(self):return self.userdef __repr__(self):return unicode_to_repr('%s()' % self.__class__.__name__)
自定义字段
- 该方法的命名为get_加上要序列化的字段
```python
goods = serializers.SerializerMethodField()
#该方法的命名为get_加上要序列化的字段
def get_ad_goods(self, obj):print('get_ad_goods', obj.id)goods_json = {}# 这里传过来的只有'蔬菜水果','酒水饮料','粮油副食','生鲜食品'# 而他们的序号已经在IndexAd表中添加过了,所有会找到队友的商品纪录ad_goods = IndexAd.objects.filter(category_id=obj.id, )if ad_goods:good_ins = ad_goods[0].goods# 在serializer的方法中使用Serializer的时候,他会检察上下文中有没有包含request,# 如果有,那么在返回的图片url中会自动加上域名 http://....# 如果没有,那么返回的url只会加上路径 /media/goods/images/......goods_json = GoodsSerializer(good_ins, many=False, context={'request': self.context['request']}).datareturn goods_json
2、ModelSerializer
class Meta:model = Goods# field = ('name','click_num','add_time') # 返回给前端的json中包含的字段field = "__all__" # 包含所有字段
- 重写create方法进行持久化操作
def create(self, validated_data):"""Create and return a new `Good` instance, given the validated data."""return Goods.objects.create(**validated_data)
- 直接使用外键主键作为值 PrimaryKeyRelatedField
goods = serializers.PrimaryKeyRelatedField(queryset=Goods.objects.all(),required=True)
这里的外键与直接写一个类不同的是,只会将主键(goods_id)返回给前端,而不是返回goods中的所有字段。
- 引入外键的序列化类,序列化外键表中的信息
class GoodCategorySerializer2(serializers.ModelSerializer):'''二级分类'''sub_cat = GoodCategorySerializer3(many=True)class Meta:model = GoodCategoryfields = "__all__" # 包含所有字段class GoodCategorySerializer(serializers.ModelSerializer):'''一级分类'''# sub_cat 是Category表中的自关联字段parent_category的relate_name,# 用于一对多反向引用时,点出二级分类,配置在一的那一方# 找出所有parent_category等于当前这个一级分类的parent_category的二级分类# many=True 表示会有多个sub_cat = GoodCategorySerializer2(many=True)class Meta:model = GoodCategoryfields = "__all__" # 包含所有字段
- many=True (一般用于反向查询)
class GoodsSerializer(serializers.ModelSerializer):category = GoodCategorySerializer()# images为GoodImage中外键的relate_name,用于反向查询images = GoodsImageSerializer(many=True) # 反向查询,一对多
- many=False (一般用于正向查询)
# 这个表保存的是每个订单的每个商品数据
class OrderGoodsSerialzier(serializers.ModelSerializer):# 每个订单下的相同商品只会存在一条纪录# goods是OrderGoods中的外键goods = GoodsSerializer(many=False)class Meta:model = OrderGoodsfields = "__all__"
- 对应的OrderGoods
class OrderGoods(models.Model):"""订单商品信息"""order = models.ForeignKey(OrderInfo, verbose_name="订单信息",related_name="order_goods",on_delete=models.CASCADE)goods = models.ForeignKey(Goods, verbose_name="商品", on_delete=models.CASCADE)goods_sum = models.IntegerField(default=0, verbose_name="商品数量")add_time = models.DateTimeField(default=datetime.now, verbose_name="添加时间")
注意:字段定义之后,如果也定义了meta类,则必须在类中的fields元祖中添加字段,或者写成fields = “all”
字段中的参数使用
以这块代码为例
'''负责用户注册时的初始化验证操作'''code = serializers.CharField(required=True, write_only=True, max_length=4, min_length=4,label="验证码",error_messages={"blank": "请输入验证码","required": "请输入验证码","max_length": "验证码格式错误","min_length": "验证码格式错误"},help_text="验证码")username = serializers.CharField(label="用户名", help_text="用户名", required=True, allow_blank=False,validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")])password = serializers.CharField(style={'input_type': 'password'},help_text="密码", label="密码", write_only=True,)add_time = serializers.DateTimeField(read_only=True, format='%Y-%m-%d %H:%M')
read_only和write_only
注意:read_only=True 这个值只返回给前端不让前端提交,前端只有读的权利
write_only=True 这个值让前端只会提交,不会再返回给前端,前端只有写的权利
format 序列化输出的格式 validators 指定验证器
验证是否唯一
validators=[UniqueValidator(queryset=User.objects.all(), message="用户已经存在")
自定义字段验证规则
mobile = serializers.CharField(max_length=11)def validate_mobile(self, mobile):'''验证手机号码:param mobile::return:'''# 手机号是否注册if User.objects.filter(mobile=mobile).count():raise serializers.ValidationError("用户已经存在")# 验证手机号是否合法if not re.match(settings.REGEX_MOBILE,mobile):raise serializers.ValidationError('手机号码非法')# 验证验证码发送频率one_minute_ago = datetime.now() - timedelta(hours=0,minutes=1,seconds =0)if VerifyCode.objects.filter(add_time__gt=one_minute_ago,mobile=mobile).count():raise serializers.ValidationError('请超过60s后再次发送')return mobile
验证整体数据
def validate(self, attrs):attrs["mobile"] = attrs["username"] # 整体验证del attrs["code"] return attrs
联合唯一的验证
class Meta:model = UserFavvalidators = [UniqueTogetherValidator(queryset=UserFav.objects.all(),fields=('user', 'goods'),message="已经收藏")]
重写crete方法
例:
主要是让其通过CreateMixin中的验证,源码如下
serializer = self.get_serializer(data=request.data)
serializer.is_valid(raise_exception=True)
重写Serilizer中的create
# 这里不用ModelSerializer的原因是, 这里需要使用user, goods联合索引## 我们当然可以使用联合索引来控制唯一性,但问题是,当我们重复添加商品时(只是希望他更新nums字段时(但是实际上是用update方法更新的)),# 第二条就会报错,因为会验证失败,所以我们不能再此使用联合索引,而需要使用更加灵活的Serializer并重写create方法## 如果是ModelSerializer, 那么重复添加同一个商品时View中继承的CreateMinx中create方法中的验证就会报错 == serializer.is_valid(# raise_exception=True) == 报错(因为是联合索引)## 这样就不会再执行serializer.save()# 方法保存了,所有这里必须使用Serializer,重写create方法,而不使用联合索引## 总结,使用联合索引时,如果需要重复创建商品,但实际上只更新某个字段,CreateMinx中的create方法验证不通过,必须使用Serializer,重写create方法def create(self, validated_data):# 拿到user,nums,gooduser = self.context['request'].usernums = validated_data['nums']goods = validated_data['goods']existed = ShoppingCart.objects.filter(user=user,goods=goods)if existed:existed = existed[0]# existed.objects.update(nums=(nums+1)) 不可以,报错existed.nums += numsexisted.save()else:existed = ShoppingCart.objects.create(**validated_data)return existed #必须返回一个实例
重写update方法。通过Update中的验证
def update(self, instance, validated_data):# 修改商品数量instance.nums = validated_data['nums']instance.save()return instance #必须返回一个实例
tips:通常将serializer中的方法和Mixins中的方法结合起来看,因为Minix中会调用Serializer中的方法
initial_data 和 validated_data
- init_data 指的是最原始的没有经过验证的数据
- validated_data 指定是已经验证转换过的数据,比如nums已经验证无误并转换成了int类型
在Serializer中拿到request对象
# 拿到user,nums,gooduser = self.context['request'].usernums = validated_data['nums']goods = validated_data['goods'] # 这里取出的goods是Good对象
Serializer类与Mixin的执行顺序源码分析
这里以CreateMixin为例
CreateModelMixinclass CreateModelMixin(object):"""Create a model instance."""def create(self, request, *args, **kwargs):print('createModel Mixin......')serializer = self.get_serializer(data=request.data)serializer.is_valid(raise_exception=True)self.perform_create(serializer)headers = self.get_success_headers(serializer.data)return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers)def perform_create(self, serializer):print('perform_date')serializer.save()def get_success_headers(self, data):try:return {'Location': str(data[api_settings.URL_FIELD_NAME])}except (TypeError, KeyError):return {}serializer.save()if self.instance is not None:self.instance = self.update(self.instance, validated_data)assert self.instance is not None, ('`update()` did not return an object instance.')else:self.instance = self.create(validated_data)assert self.instance is not None, ('`create()` did not return an object instance.')
打印的结果是:
createModel Mixin...... 首先执行CreateMixin
is_valid....... 执行BaseSerializer中的is_vaild
perform_date 执行CreateMixin的performdata
Base Serializer save...... 执行BaseSerializer中的save
ModelSerializer create......... 执行ModelSerializer中的create
is_valid....... 在BrowsableAPIRenderer类中调用了serializer.is_valid
注意:最后一次的is_valid执行是与权限类permissions有关,在BrowsableAPIRenderer类中会执行
def render_form_for_serializer(self, serializer):if hasattr(serializer, 'initial_data'):serializer.is_valid()
Serializer及ModelSerializer的使用相关推荐
- DAY97 - Rest Framework(二)- 序列化组件之Serializer和ModelSerializer
一.序列化组件之Serializer from django.http import JsonResponse from rest_framework.views import APIView fro ...
- 5.Serializer,ModelSerializer区别
Serializer示例代码: # 使用Serializer class BookSerializer(serializers.Serializer):id = serializers.Integer ...
- djangorestframework源码分析2:serializer序列化数据的执行流程
djangorestframework源码分析 本文环境python3.5.2,djangorestframework (3.5.1)系列 djangorestframework源码分析-serial ...
- Django REST framework 1
Django REST framework Django REST framework官方文档:点击 中文文档:点击 安装djangorestframework:pip3 install djang ...
- Django Rest Framework
新的一年启程,大家又投入到紧张的学习和工作中,作为一个互联网人必须时刻紧跟科技发展的脚步.对于大火的 Python 编程语言我们怎么能错过,我们[51Reboot]这就为大家带来新年的第一堂 Pyth ...
- Django RestFramework BaseSerializer
BaseSerializer类,该类可用于轻松支持可选序列化和反序列化样式. 此类实现与Serializer类具有相同的基本API: .data - 返回传出基元表示形式. .is_valid() - ...
- Django REST framework API开发
REST 介绍 RESTful API 设计 实现API的两种方式 FBV 视图函数 urlpatterns = [url(r'^user/$', views.user),url(r'^user/ad ...
- rest_framework-序列化-总结完结篇
#rest_framework 序列化 from rest_framework import serializers#serilizers.Serializer serializers.ModelSe ...
- Django restful Framework 之序列化与反序列化
1. 首先在已建好的工程目录下新建app命名为snippets,并将snippets app以及rest_framework app加到工程目录的 INSTALLED_APPS 中去,具体如下: IN ...
- Serializers
serializers.py 序列化器 串行器允许诸如查询集和模型实例复杂的数据转换为可随后被容易地呈现到机Python数据类型JSON,XML或其他内容类型.序列化器还提供反序列化,允许解析的数据在 ...
最新文章
- 体检系统前端源码_给您的前端进行健康检查
- tomcat启动命令行窗口出现乱码的解决方法
- 石头扫地机器人离线了怎么办_关于激光头故障,石头扫地机器人无限次复活记!...
- 龙芯派启用串口3-5
- python中mainloop添加背景_Python实例讲解 - tkinter canvas (设置背景图片及文字)
- oracle之高级子查询之课后练习
- mat 释放_Square Ma?mat住宅区:释放公共空间,连接社区居民
- 手写原笔迹输入_手写原笔迹
- k3安装服务器系统,论如何逗比的在2008R2上安装金蝶K3服务器
- 南大计算机面经(结果:WaitList)
- 程序员界之行业求职黑名单!实用!
- 利用win自带功能让处于同一局域网的两个电脑之间互传文件(速度和本地磁盘间互传相同)
- linux ohmyzsh shell主题包以及修改shell命令
- turtle库使用——漫天繁星+万花筒绘制
- 计算机设计大赛数媒民族元素类,北京工业大学艺术设计学院
- 谷歌推出以太坊区块链的大数据视图
- vivo新系统鸿蒙,截胡华为鸿蒙系统!vivo霸气官宣新系统将登场:天生极致流畅...
- 2006年3月11日下午15点30分左右 偶的BLOG终于上路了^_^
- SQL Server修改字段修改描述语句
- 分布式系统设计理论之一致性哈希