【Django学习】(九)自定义校验器_单字段_多字段校验_模型序列化器类

news2025/1/11 2:58:01

 之前学习了视图集里运用序列化器进行序列化和反序列化操作,定义序列化器类,需要继承Serializer基类或者Serializer的子类;

这次我们将学习如何自定义校验器、如何进行单字段或者多字段校验,最后初步使用模型序列化器

一、自定义校验器

比如定义一个校验项目名称字段是否包含“项目”的函数:

def is_contain_project_word(value):
    if "项目" not in value:
        raise serializers.ValidationError("项目名称里必须包含'项目'")
  • 在定义字段属性时候,有时候会用到校验器validators参数;
  • validators参数只能为列表或者元素,列表或者元组中的每一个元素,为一个约束条件
  • 可以使用UniqueValidator来指定唯一约束条件,第一个参数为查询集对象,message关键字参数可以指定具体的报错信息
  • 如果校验不通过,必须得返回一个serializers.ValidationError对象,并且可以指定具体的报错提示信息

 将自定义的校验函数添加到校验器列表中:

class ProjectSerializer(serializers.Serializer):
    id = serializers.IntegerField(label="id主键", help_text="id主键", read_only=True)
    name = serializers.CharField(label="接口名称", help_text="接口名称", max_length=10, min_length=5,
                                 validators=[UniqueValidator(ProjectsModel.objects.all(), message="项目名称不可重复!"),
                                             is_contain_project_word])

二、单字段校验

除了上面的自定义校验器可以进行单字段校验外,我们还可以在序列化器类中使用validate_作为前缀,然后加上字段名称定义的方法 对单字段进行校验

    def validate_name(self, value):
        if not value.endswith("项目"):
            return serializers.ValidationError("项目名称必须以'项目'结尾!")
        return value

上面是针对name字段进行校验,验证是否以“项目”结尾 

  • 如果校验通过,则必须返回校验通过后的值(例如上面的return value),如果不返回则后面接收到的值为None,会产生异常并报错
  • 如果校验不通过,则调用serializers.ValidationError,返回自定义的报错信息(例如上面的"项目名称必须以'项目'结尾!")

三、多字段校验

  • 可以在validate方法中,对多个字段进行校验
  • 第二个参数为上面校验通过之后的数据(字典类型)
  • 必须得返回校验通过之后的值
    def validate(self, attrs):
        project_leaders=attrs.get('leaders')
        project_name=attrs.get('name')
        if '花生' not in project_leaders or len(project_name) <= len(project_leaders):
            raise serializers.ValidationError('项目负责人名称必须得包含“花生”并且项目名称的长度要超过项目负责人名称')
        return attrs

序列化器serializers.py

def is_container_project_word(value):
    if '项目' not in value:
        raise serializers.ValidationError('项目名称中必须得包含“项目”')

# class ValidateProject:
#     def __call__(self, *args, **kwargs):
#         pass


class ProjectSerializer(serializers.Serializer):

    name = serializers.CharField(label='项目名称', help_text='项目名称', min_length=5, max_length=10, write_only=True,
                                 validators=[UniqueValidator(Projects.objects.all(), message='项目名不能重复'),
                                             is_container_project_word],
                                 error_messages={'min_length': '项目名称不能少于5位',
                                                 'max_length': '项目名称不能超过10位', 'required': '项目名称为必传参数'})
    leader = serializers.CharField(label='项目负责人', help_text='项目负责人',
                                   min_length=5, max_length=8)
    desc = serializers.CharField(label='简要描述', help_text='简要描述', allow_blank=True, allow_null=True,
                                 default='')
    # token = serializers.CharField(read_only=True)
    def validate_name(self, value):
        if not value.endswith('项目'):
            raise serializers.ValidationError('项目名称必须得以“项目”结尾')
        return value

    def validate(self, attrs):
        leader_name = attrs.get('leader')
        project_name = attrs.get('name')
        if '花生' not in leader_name or len(project_name) <= len(leader_name):
            raise serializers.ValidationError('项目负责人名称必须得包含“花生”并且项目名称的长度要超过项目负责人名称')
        return attrs

    def create(self, validated_data):
        pro = Projects.objects.create(**validated_data)
        return pro

    def update(self, instance, validated_data):
        instance.name = validated_data.get('name')
        instance.leader = validated_data.get('leader')
        instance.desc = validated_data.get('desc')
        instance.save()
        instance.token = 'shisdhisfhishfisfh'
        return instance

 四、优化(视图集与模型类序列化器)

因为视图集里面很多操作都是重复的,比如序列化与反序列化操作;序列化器里的字段和对应的参数也需要重复设置,无形中增加了代码量

 所以这次将对序列化器和视图集进行一次优化升级,缩减代码量

4.1优化的视图集views.py

class ProjectDetailView(View):
    def get_object(self, pk):
        ret = {
            "msg": "参数异常",
            "code": 0
        }

        # 数据校验(校验项目id是否存在)
        try:
            return Projects.objects.get(pk=pk)
        except Exception:
            raise Http404

    def get(self, request, pk):

        pro = self.get_object(pk)
        serializer_obj = ProjectSerializer(instance=pro)
        return JsonResponse(serializer_obj.data, json_dumps_params={"ensure_ascii": False})

    def put(self, request, pk):
        ret = {
            "msg": "参数异常",
            "code": 0
        }

        pro = self.get_object(pk)

        json_data = request.body.decode('utf-8')
        try:
            python_data = json.loads(json_data)
        except json.JSONDecodeError:
            return JsonResponse(ret, status=400, json_dumps_params={"ensure_ascii": False})

        # a.在创建序列化器对象时,如果同时给instance与data传参,那么序列化器对象调用save()方法时,会自动调用update()方法
        serializer_obj1 = ProjectSerializer(instance=pro, data=python_data)
        try:
            serializer_obj1.is_valid(raise_exception=True)
        except:
            ret.update(serializer_obj1.errors)
            return JsonResponse(ret, status=400, json_dumps_params={"ensure_ascii": False})

        # 更新数据
        # a.如果给save传递参数,会自动将参数合并到validated_data中
        # b.如果传递重复参数,那么会将之前的前端传递的参数覆盖
        #serializer_obj1.save(age=18, name='唯一Love')
        serializer_obj1.save()

        return JsonResponse(serializer_obj1.data, json_dumps_params={"ensure_ascii": False})

    def delete(self, request, pk):
        ret = {
            "msg": "参数异常",
            "code": 0
        }

        pro = self.get_object(pk)
        pro.delete()

        # 返回数据
        return JsonResponse(None, safe=False, status=204)


class ProjectView(View):
    def get(self, request):
        # 获取所有的项目数据
        qs = Projects.objects.all()

        serializer_obj = ProjectSerializer(instance=qs, many=True)
        return JsonResponse(serializer_obj.data, json_dumps_params={"ensure_ascii": False})

    def post(self, request):
        ret = {
            "msg": "参数异常",
            "code": 0
        }
        # 获取json格式的字符串数据
        json_data = request.body.decode('utf-8')
        try:
            python_data = json.loads(json_data)
        except json.JSONDecodeError:
            return JsonResponse(ret, status=400, json_dumps_params={"ensure_ascii": False})
        # b.在创建序列化器对象时,如果只给data传参,那么序列化器对象调用save()方法时,会自动调用create()方法
        serializer_obj1 = ProjectSerializer(data=python_data)

        try:
            serializer_obj1.is_valid(raise_exception=True)
        except:
            ret.update(serializer_obj1.errors)
            return JsonResponse(ret, status=400, json_dumps_params={"ensure_ascii": False})

        serializer_obj1.save()
 
        return JsonResponse(serializer_obj1.data, json_dumps_params={"ensure_ascii": False})

 上面代码中,反序列化输入与序列化输出

  • 序列化输出
    • 将模型类对象传递给instance,会返回一个序列化器类对象,
      • 例如:serializer_obj = ProjectSerializer(instance=pro)
    • 如果传递的是查询集对象,那么需要添加many=True
      • 例如:serializer_obj = ProjectSerializer(instance=pro,many=True)
    • 可以使用序列化器对象的data属性,获取序列化之后的数据(字典或者嵌套字典的列表)
      • 例如:
            def get(self, request, pk):
                pro=self.get_object(pk)
                serializer_obj=ProjectModelSerializer(instance=pro)
                return JsonResponse(serializer_obj.data,json_dumps_params={"ensure_ascii": False})

  • 反序列化输入
    • 将字典类型或者(嵌套字典的列表)传递给data参数,会返回一个序列化器类对象
    • 必须先调用序列化器类对象.is_valid()方法,才会开始校验参数,检验成功会返回True,否则返回False
    • 可以使用序列化器类对象.errors属性,获取报错信息(字典类型)
    • 可以使用序列化器类对象.validated_data属性,获取校验通过之后的数据
  • 创建数据,返回模型类对象
    • 模型类对象在调用save()方法时,会自动调用create()方法
    • 如果序列化器对象调用save()方法时传递关键字参数进去,那么在自动调用create()方法时,自动合并到validated_data中
    • 如果不调用save()方法,则不会调用create方法和update方法,输出时候是以validated_data里的数据进行输出的(适用于查询操作)

4.2优化序列化器类

之前是序列化器类,这次优化使用成模型序列化器类

  • 可以继承ModelSerializer类或者ModelSerializer的子类,来创建模型序列化器类
  • 来通过指定的模型类,来自动生成序列化器字段以及相关校验规则

class ProjectModelSerializer(serializers.ModelSerializer):

    # a.必须得在Meta内部类中使用model属性指定,参考的模型类
    # b.可以使用fields属性来指定哪些模型类中的字段,需要自动生成序列化器字段
    class Meta:
        model = Projects
        # c.指定所有的字段
        # fields = '__all__'
        # d.可以将需要自动生成序列化器字段的模型类字段添加到元组中
        fields = ('name', 'leader','tester')
        def validate_name(self, value):
        if not value.endswith("项目"):
            return serializers.ValidationError("项目名称必须以'项目'结尾!")
        return value
        # 如果不返回value,结果则为None

    def validate(self, attrs):
        project_leaders = attrs.get('leaders')
        project_name = attrs.get('name')
        if '花生' not in project_leaders or len(project_name) <= len(project_leaders):
            raise serializers.ValidationError('项目负责人名称必须得包含“花生”并且项目名称的长度要超过项目负责人名称')
        return attrs

    def create(self, validated_data):
        return ProjectsModel.objects.create(**validated_data)

    def update(self, instance, validated_data):
        # 修改老数据,传入新数据给对应字段
        instance.name = validated_data.get("name")
        instance.leader = validated_data.get("leader")
        instance.desc = validated_data.get("desc")
        instance.programmer = validated_data.get("programmer")
        instance.tester = validated_data.get("tester")
        instance.publish_app = validated_data.get("publish_app")
        instance.save()

        return instance

所以上面的views.py文件内的代码还可以优化:将创建序列化器对象时调用 ProjectSerializer替换成 ProjectModelSerializer

debug跑通截图:

 

 这个时候初步实现了视图集和序列化器的优化,后面还会继续针对模型序列化器类进行优化

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/701456.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

OPPO手机无网络可支持3km通信,对讲机将被淘汰?

OPPO在2019世界移动通信大会即MWC上海发布了一项新技术&#xff0c;被称为“无网络通信技术”&#xff08;MeshTalk&#xff09;。这是OPPO自主研发的一项去中心化通讯技术&#xff0c;能够在没有蜂窝网络、Wi-Fi、蓝牙的情况下&#xff0c;实现3km内通讯。 无网通信技术 不过…

Java教程-Java异常抛出

在Java中&#xff0c;异常允许我们编写高质量的代码&#xff0c;可以在编译时检查错误而不是在运行时&#xff0c;并且我们可以创建自定义异常&#xff0c;使代码的恢复和调试更加容易。 Java的throw关键字 Java的throw关键字用于显式地抛出异常。 我们指定要抛出的异常对象。异…

华为breeze ideploy部署流程示例

https://www.cnblogs.com/withfeel/p/11640877.html 华为breeze ideploy部署流程示例

Canal对MySQL进行数据迁移

Canal简单介绍 贴个官方网址&#xff1a;阿里巴巴MySQL binlog 增量订阅&消费组件 架构图&#xff1a; 基于日志增量订阅和消费的业务包括 数据库镜像数据库实时备份索引构建和实时维护(拆分异构索引、倒排索引等)业务 cache 刷新带业务逻辑的增量数据处理 当前的 cana…

CSS知识点汇总(十一)--回流重绘

文章目录 怎么理解回流跟重绘&#xff1f;什么场景下会触发&#xff1f;1、回流和重绘是什么&#xff1f;2、如何触发回流和重绘3、如何避免回流和重绘的发生 怎么理解回流跟重绘&#xff1f;什么场景下会触发&#xff1f; 1、回流和重绘是什么&#xff1f; 在HTML中&#xf…

二十、socket套接字编程(二)——TCP

文章目录 一、TCP套接字接口&#xff08;一&#xff09;inet_aton &#xff08;和inet_addr一样&#xff0c;换一种方式而已&#xff09;&#xff08;二&#xff09;socket()&#xff08;三&#xff09;bind()&#xff08;四&#xff09;listen()&#xff08;五&#xff09;acc…

ASP.NET Core MVC -- 入门

先决条件&#xff08;开发配置二选一&#xff09;&#xff1a; 带有 ASP.NET 和 Web 开发工作负载的Visual Studio Visual Studio Code Visual Studio Code用于 Visual Studio Code 的 C#&#xff08;最新版本&#xff09;.NET 7.0 SDK 创建Web应用 visual studio ctrl F5 …

云原生之深入解析Kubernetes网络流量的流转路径

一、Kubernetes 网络要求 Kubernetes 网络模型定义了一组基本规则&#xff1a; 在不使用网络地址转换 (NAT) 的情况下&#xff0c;集群中的 Pod 能够与任意其他 Pod 进行通信&#xff1b; 在不使用网络地址转换 (NAT) 的情况下&#xff0c;在集群节点上运行的程序能与同一节点…

王道《计算机网络》思维导图汇总

第一章 1.1.1 概念与功能 1.1.2 组成与分类 1.1.3 标准化工作及相关组织 1.1.4 性能指标 速率 带宽 吞吐量 时延 时延带宽积 往返时延RTT 利用率 1.2.1 分层结构、协议、接口、服务 1.2.2 OSI参考模型 应用层 表示层 会话层 传输层 网络层 数据链路层 物理层 1.2.4 TCP/IP 参…

内核角度看IO模型

聊聊Netty那些事儿之从内核角度看IO模型 网络包接收流程 当网络数据帧通过网络传输到达网卡时&#xff0c;网卡会将网络数据帧通过DMA的方式放到环形缓冲区RingBuffer中。RingBuffer是网卡在启动的时候分配和初始化的环形缓冲队列。当RingBuffer满的时候&#xff0c;新来的数据…

【AUTOSAR】BMS开发实际项目讲解(十三)----电池管理系统碰撞安全功能和SFR

SG-BMS-7 : BMS系统应避免碰撞保护功能异常引起的安全事故&#xff08;ASIL A&#xff09; 功能框图&#xff08;SG-BMS-7&#xff09; 功能组件说明 功能组件ID 功能组件名称 描述 ASIL等级 FSC-FC-05 Relay Drive 驱动继电器开启和关断 ASIL A FSC-FC-11 Detection …

【vue】可选链运算符(?.)和空值合并运算符(??):

文章目录 一、问题一:二、问题二:三、使用:【1】空值合并运算符&#xff08;??&#xff09;【2】可选链运算符&#xff08;?.&#xff09; 一、问题一: http://www.codebaoku.com/question/question-sd-1010000042870944.html //1、npm安装 npm install babel/plugin-propo…

批量修改文件命名的shell脚本

Android 制作开机动画的方法参考&#xff1a;linux开机动画制作教程 其中往往会把里面的png图片命名位XX_0001.png , 002.png……等 Window批量修改文件名时会带有空格和括号。 这里写了一个脚本&#xff0c;可以在批量修改文件名后&#xff0c;将文件名转换为XX_00001 格式&…

基于matlab使用 YOLO V2深度学习进行多类对象检测(附源码)

一、前言 此示例演示如何训练多类对象检测器。 深度学习是一种强大的机器学习技术&#xff0c;可用于训练强大的多类对象检测器&#xff0c;例如 YOLO v2、YOLO v4、SSD 和 Faster R-CNN。此示例使用该函数训练 YOLO v2 多类室内对象检测器。经过训练的物体检测器能够检测和识…

ModaHub魔搭社区:Milvus 监控指标和使用 Grafana 展示 Milvus 监控指标

目录 Milvus 监控指标 Milvus 性能指标 系统运行指标 硬件存储指标 Milvus 监控指标 Milvus 会生成关于系统运行状态的详细时序 metrics。你可以通过 Prometheus、Grafana 或任何可视化工具展现以下指标&#xff1a; Milvus 性能指标系统运行指标&#xff1a;CPU/GPU 使用…

单片机学习 11-中断系统(定时器中断+外部中断)

中断系统 中断介绍 ​ 中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的&#xff0c;中断功能的存在&#xff0c;很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一&#xff0c;是我们学习单片机必须要掌握的。很多初学者被困在…

全网超全,Pytest自动化测试框架pytest-xdist分布式测试插件(实战)

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 平常我们功能测试…

Markdown 扩展语法

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&…

Python在命令行模式下如何退出命令行

文章目录 python退出命令行模式结语 刚学习python的时候是用的命令行的方式&#xff0c;刚接触不知道如何退出命令行&#xff0c;百度参考了好几篇文章&#xff0c;这里记录一下&#xff0c;希望能帮助到有需要的小伙伴们。 python退出命令行模式 总结一下&#xff0c;共有三种…

Redis处理⾼并发 实现分布式锁

Redisson Redisson是架设在Redis基础上的⼀个Java驻内存数据⽹格&#xff08;In-Memory Data Grid&#xff09;。 Redisson在基于NIO的Netty框架上&#xff0c;充分的利⽤了Redis键值数据库提供的⼀系列优势&#xff0c;在Java实⽤⼯具包中常⽤ 接⼝的基础上&#xff0c;为使⽤…