前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >python测试开发django-rest-framework-88.反序列化

python测试开发django-rest-framework-88.反序列化

作者头像
上海-悠悠
发布2021-02-03 10:03:38
6490
发布2021-02-03 10:03:38
举报
文章被收录于专栏:从零开始学自动化测试

前言

serializers.Serializer可以对modle模型中的字段序列化,并且必须写create和update两个方法。ModelSerializer可以看成是Serializer的一个升级版,功能更强大,更方便。 实际上ModelSerializer类继承了Serializer类

序列化

序列化是把数据库里面的数据,转成json格式返回给用户,具体参考前面这篇https://www.cnblogs.com/yoyoketang/p/11538172.html 在models.py设计一个Goods商品表,里面包含多个字段和多个数据类型

代码语言:javascript
复制
from django.db import models
# Create your models here.
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

class Goods(models.Model):
    """商品表"""
    goods_name = models.CharField(max_length=30,
                                  default="",
                                  verbose_name="商品名称")
    goods_code = models.CharField(max_length=30,
                                  unique=True,
                                  verbose_name="商品代号")
    merchant_id = models.CharField(max_length=30,
                                   default="",
                                   blank=True, null=True,
                                   verbose_name="商户ID")
    merchant_name = models.CharField(max_length=30,
                                     default="",
                                     blank=True, null=True,
                                     verbose_name="商户名称")
    goods_price = models.FloatField(blank=True, null=True,
                                    default=0,
                                    verbose_name="商品价格")
    goods_stock = models.IntegerField(blank=True, null=True,
                                      default=0,
                                      verbose_name="商品库存")
    goods_groupid = models.IntegerField(blank=True, null=True,
                                        default=0,
                                        verbose_name="商品分组")
    goods_status = models.IntegerField(choices=(
                                                (0, '下架'), 
                                                (1, '出售中')
                                               ),
                                       default=1,
                                       verbose_name="0下架 1出售中")

    price = models.FloatField(blank=True, null=True,
                              default=0,
                              verbose_name="成本价")

    create_time = models.DateTimeField(auto_now_add=True, verbose_name="添加时间")
    update_time = models.DateTimeField(auto_now=True, verbose_name="修改时间")

    class Meta:
        verbose_name_plural = '商品'
        verbose_name = "商品信息"

    def __str__(self):
        return self.goods_code

view视图

视图继承 drf 的 APIView,这里写了2个方法,get 查询全部商品,序列化后返回json数据。 post 请求是创建商品。

代码语言:javascript
复制
from rest_framework.views import APIView
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.permissions import AllowAny, IsAuthenticated, IsAdminUser
from rest_framework.authentication import TokenAuthentication
from .models import Goods

# Create your views here.
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段
        # exclude是不包含某些字段
        # exclude = ["price"]

class GoodsAPIView(APIView):
    """商品视图"""
    permission_classes = (AllowAny,)      # AllowAny 允许所有用户

    def get(self, request, *args, **kwargs):
        """返回所有的"""
        goods = Goods.objects.all()   # 查询全部
        serializer = GoodsSerializer(instance=goods, many=True)

        return Response({
            "code": 0,
            "msg": "success!",
            "data": serializer.data
        })

    def post(self, request, *args, **kwargs):
        """提交数据"""
        verify_data = GoodsSerializer(data=request.data)
        if verify_data.is_valid():
            save = verify_data.save()
            return Response({
                "code": 0,
                "msg": "success!",
                "data": GoodsSerializer(instance=save).data
            })
        else:
            return Response({
                "code": 10086,
                "msg": "参数不合法",
                "data": verify_data.errors
            })

urls.py配置访问路由

代码语言:javascript
复制
from django.conf.urls import url
from yoyo import views

urlpatterns = [
    url('^api/v1/goods/$', views.GoodsAPIView.as_view()),
]

序列化和反序列化

什么是序列化呢?

当用户需要查询数据的时候,把数据库里面的数据转成我们需要的json数据,这个过程就是序列化

在get方法里实例化GoodsSerializer对象,传2个参数

  • instance 是查询的queryset对象,也可以是单个Goods 的object对象
  • many 如果是queryset对象,就需要带上many=True ,说明是一个list,有多个数据,如果是单个object对象,就不需要这个参数
代码语言:javascript
复制
    def get(self, request, *args, **kwargs):
        """返回所有的"""
        goods = Goods.objects.all()   # 查询全部
        serializer = GoodsSerializer(instance=goods, many=True)

上面这个过程就是序列化,序列化后输出数据serializer.data

什么是反序列化?

用户在添加商品的时候,需要把数据存到数据库,这个过程我们需要先校验是不是合法的。

对用户传入的数据,我们需要先清洗下,因为用户可能会传一些数据库表里面没有的字段,这些我们不需要,于是可以用到 GoodsSerializer(data=request.data)

data 用户传入的参数,通过request.data 获取,request.data 实际上跟之前request.POST 是一样的获取用户传过来的数据

is_valid() 校验数据是否合法

save() 保存之前,必须先调用is_valid(),保存后返回一个Goods object对象

上面这个过程,用户传过来的数据先清洗,校验数据合法性,再存入数据库的过程,就是反序列化

校验用户数据必传项required=True

看过接口文档的应该知道,有些参数是必传的,有些是非必传的,那么我们可以在GoodsSerializer控制字段的必传和非必传 详情参考前面这篇https://www.cnblogs.com/yoyoketang/p/14291206.html

代码语言:javascript
复制
class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    # 必传字段
    goods_code = serializers.CharField(required=True)
    goods_stock = serializers.IntegerField(required=True)

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段

序列化的时候,设置 goods_code 和 goods_stock 是必传字段,那么在添加商品的时候,如果不传就会提示

代码语言:javascript
复制
{"goods_code":["该字段是必填项。"],"goods_stock":["该字段是必填项。"]}}

校验忽略某些字段read_only=True

如果在创建商品的时候,有些字段我不想让用户去修改,比如 goods_status(商品状态),默认就是出售中,

不想让用户创建的时候设置下架,于是可以忽略 goods_status(商品状态) 字段, 设置 read_only=True

代码语言:javascript
复制
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    # 必传字段
    goods_code = serializers.CharField(required=True)
    goods_stock = serializers.IntegerField(required=True)

    # 忽略字段,设置read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段

现在不管 goods_status 传什么都不会影响保存结果

校验字符串和整数范围

校验 goods_code 字符串长度是8-15位,校验goods_stock 整数范围是1-10000

代码语言:javascript
复制
class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    # 必传字段
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # 忽略字段,设置read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段

这时候就会对传入的字符串和整数范围做校验

自定义校验字段

如果我想用户的商品code命名,必须按sp开头,针对某个字段单独写校验方式,可以自定义 validate_<field_name>

  • value 参数是传入的数据
  • raise 抛出的异常会serializers.ValidationError(“goods_code 不是 sp 开头”), 会在 verify_data.errors显示
代码语言:javascript
复制
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    # 必传字段
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # 忽略字段,设置read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    def validate_goods_code(self, value):
        """校验字段 validate_<Field>"""
        if not value.startswith("sp"):
            raise serializers.ValidationError("goods_code 不是 sp 开头")
        return value

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段

多个字段校验

如果我想校验 goods_price(商品售卖价格)不能小于 (price)成本价, 万一哪个运营设置商品价低于成本价,那不得亏惨! 这里涉及到传入参数的2个值互相校验

代码语言:javascript
复制
# 作者-上海悠悠 QQ交流群:717225969
# blog地址 https://www.cnblogs.com/yoyoketang/

class GoodsSerializer(serializers.ModelSerializer):
    """序列化商品models"""
    create_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)
    update_time = serializers.DateTimeField(format='%Y-%m-%d %H:%M:%S',required=False)

    # 必传字段
    goods_code = serializers.CharField(required=True,
                                       max_length=15,
                                       min_length=8)
    goods_stock = serializers.IntegerField(required=True,
                                           min_value=1,
                                           max_value=10000)

    # 忽略字段,设置read_only=True
    goods_status = serializers.IntegerField(read_only=True)

    def validate_goods_code(self, value):
        """校验字段 validate_<Field>"""
        if not value.startswith("sp"):
            raise serializers.ValidationError("goods_code 不是 sp 开头")
        return value

    def validate(self, attrs):
        """自定义校验"""
        goods_price = attrs.get('goods_price', 0)
        price = attrs.get('price', 0)
        if goods_price < price:
            raise serializers.ValidationError('goods_price 不能小于 price')
        return attrs

    class Meta:
        model = Goods
        fields = '__all__'  # 返回全部的字段
本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2021-01-29,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 从零开始学自动化测试 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 序列化
  • view视图
  • 序列化和反序列化
  • 校验用户数据必传项required=True
  • 校验忽略某些字段read_only=True
  • 校验字符串和整数范围
  • 自定义校验字段
  • 多个字段校验
相关产品与服务
文件存储
文件存储(Cloud File Storage,CFS)为您提供安全可靠、可扩展的共享文件存储服务。文件存储可与腾讯云服务器、容器服务、批量计算等服务搭配使用,为多个计算节点提供容量和性能可弹性扩展的高性能共享存储。腾讯云文件存储的管理界面简单、易使用,可实现对现有应用的无缝集成;按实际用量付费,为您节约成本,简化 IT 运维工作。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档