• 测试平台系列(31) 编写环境配置页面(上)


    大家618好呀!

    这个系列好像更新进度很慢了,最近主要以水文为主。今天天气比较差,打算来点干货。恰巧饭哥也在坐台(坐在讲台),所以我就不客气了!

    编写环境管理页面

    之前的篇幅里面说过,用例没有根据环境去划分它的归属,其实这样也是不太合理的,毕竟不同的环境需要的数据可能不一致,并不一定能编写完全通用的用例。所以今天我打算从这个页面下手,手把手教大家编写一个完整的CRUD功能(带前端+联调)。后面前端的部分,如果大家不感兴趣的话,只看后端就好了。因为会有一系列的截图!看完不说半条命,那半小时肯定没了。

    有的人可能不理解,环境不就是那几套吗?测试/预发/线上等等。是的,但是各个公司会叫不同的名字,所以我们为了制作一款大众且通用的工具,所以提供他们维护自己环境的功能。

    CRUD/CURD是什么

    经常逛脉脉的同学肯定都知道,经常能看到CURD CRUD CRUD boy这样的词汇。直白点说,curd指的就是增删改查,我们今天的内容就是这个,且听我一一道来。

    • 公司最近开了一个新的环境:fat2,我们系统得维护起来,所以我们需要新增一条fat2环境的数据。

    • 公司又不用这个环境了,想去掉这个环境,免得混淆视听。

    • fat2环境公司觉得不好听,公司决定改成fat-beta。

    • 公司现在有100多种环境,太多了,需要查询是否有fat77这个环境。


    没错,其实很多开发做的功能都与这个接近。大部分时间都是在做一些crud的工作。上述是细化到我们这一次环境管理的功能点,如果你觉得难的话,耐心看完(抄完)你就不会觉得难了。

    明确思路

    首先我们先要搞清楚本次需求,其实需求很简单,就是想给用户提供自定义环境名的功能。那么我们是不是在数据库需要存储这些环境的信息。最基本的信息需要哪些呢?我这里列一下:

    数据表准备

    核心字段:

    • 环境名称

    比如fat uat pro (是否能重复?那肯定是不能重复的呀!)

    • 环境备注

    比如fat是测试环境啥的啥的,其实也可以不要,但是给你一个选项,万一你需要添加一些说明呢

    基本字段:

    • 创建人是谁
    • 修改人是谁
    • 什么时候创建的
    • 什么时候更新的
    • 被删除了木有

    功能需求准备

    • 环境可以通过名字模糊查询

    • 可以编辑,编辑后会更新编辑时间

    • 可以添加

    • 可以删除

      功能一拆分,是不是特别简单了,其实需求没多少,后端可能1小时不到就搞定了,前端还是费时间的。

    开始行动

    定义model

    既然表的字段不多,数据也不复杂,那么我们可以先定义model。

    内容不难,熟悉sqlalchemy就更轻松了。目的是为了映射一个数据表(环境表)的类

    tablename 表示当前class对应的数据库表名,我们这里为了区分,统一加上pity_前缀。
    后面的内容就是对字段的定义以及初始化类。

    生成model

    为了能自动生成数据表,我们需要在dao/init.py里面import这个model类。

    定义Pydantic的schema

    这一步的目的很简单,就是为了做参数校验,比如有的哥们很坏,他创建环境的时候,直接给你来个空字符串或者空格字符串的环境名,所以遇到这样的人,我们要鄙视他,在数据插入数据库之前就检测到,并给他沉重打击。这里熟悉pydantic的同学,都了解,不熟悉的话建议去阅读以下Pydantic的官方文档,或者照着抄就是了。

    大体意思就是定义了一个Environment的表单,里面有3个参数: id、name、remarks,对应的就是id,环境名和备注。其中name不能为空,备注随便你,写不写都行,id你也可以不传,不传就默认为None。

    编写Dao层(与db交互的核心内容)

    • 新增环境

    由于环境也算配置里面的一套内容,后续要和全局变量放到一起,所以我们给他归档到config目录下。

    来看看这个新增环境的功能都做了啥。

    首先固定搭配,这个dddd(懂的都懂)。从数据库拿到一个session,类似于db.cursor()也类似于jdbc里面的getConnection。

    with Session() as session:
    

    接着,根据我们的业务逻辑,虽然咱们数据库设置name为unique,我们还是先查询是否有这个name并且deleted_at=None(删除时间=None 代表未被删除的)的环境数据,如果有的话,我们不继续新增了,返回一个提示信息就行。

    否则呢,我们就把数据插到数据库并用session进行提交。如果中途发生异常,我们就该记录日志的记录日志,该返回错误的返回错误。如果没啥问题就返回None,代表大吉大利,相安无事

    • 编辑环境

    套路都是一样的,甚至代码也很接近。但是注意到有个区别,这里调用了update_model方法,这个方法是干啥的哩?

    我们知道,更新一条数据,我们除了需要更改的字段以外,还得有更新人和更新时间这2个字段跟着修改。所以我们编写了一套通用的方法,把你传入的data数据,改到query里面,顺便改写一下更新时间和更新人。

    not_null指的是,只更新非空字段,比如我本来有个数据是abc,你传None进来,我给他改成None了,这样可能会有误会。这里借鉴了gorm,只更新非null的字段。dist代表目标,source代表数据源。

    • 删除环境

    其实删除环境,我们这里做的是软删除,所以其实它还是一个update的操作。我们通过id找到对应的数据,把它的deleted_at改成当前时间即可,顺便改一下更新人(留下罪证)。

    • 查询环境

    注意,我这儿用的是list_env名称,为啥不是search呢?这里随你的便,我其实是把list和search合体了一下。可以看到我的name参数,如果不是None的时候,它就是个search动作,否则它是一个list操作。

    search的根本条件是,deleted_at == None,也就是说不管怎么样,咱们都得保证数据没被删除。

    if name:
        search.append(Environment.name.ilike("%{}%".format(name)))
    

    如果name有传,或者不为""也不为None,那么我们加上对name的模糊查询,等价于where name ilike xxxxx

    最后就是自动分页了,我们查出来的数据很多的话,不可能全部做展示,所以我们需要进行分页。page和size指的就是当前页码一页多少条数据

    最后咱们通过created_at进行倒序排列,也就是说最新创建的在最前面。返回一个total,就是本次查询查到了多少条数据,以便于前端进行展示。

    编写router

    router层很简单,通过ApiRouter新建路由,并把list/insert/update/delete方法注册到路由。可以看到基本上代码量很少,属于调用dao层的核心方法,根据返回结果来返回http response。

    值得注意的是,我没有用restful api去写接口,所以udpate/insert都是post请求,其他是get请求。(未出现put delete)

    注册router

    最后把刚才编写的router注册到app(pity)就可以了。

    剧透下效果:

    本期内容就到这里了,不水文虽然少点乐趣,但是hin充实呀!下一期以前端怎么curd为主,各位观众姥爷,拜了个拜!

  • 相关阅读:
    《Java并发编程的艺术》 第9章 Java中的线程池
    《Java并发编程的艺术》第6/7/8章 Java并发容器与框架/13个原子操作/并发工具类
    java锁总结
    《Java并发编程的艺术》第5章 Java中的锁 ——学习笔记
    《Java并发编程的艺术》第4章 Java并发编程基础 ——学习笔记
    Java并发编程的艺术(一、二章) ——学习笔记
    redis缓存使用SpringDataRedis
    商城06——solr索引库搭建&solr搜索功能实现&图片显示问题解决
    商城05——首页轮播图显示实现&Redis环境搭建&Redis实现缓存
    商城04——门户网站介绍&商城首页搭建&内容系统创建&CMS实现
  • 原文地址:https://www.cnblogs.com/we8fans/p/15283545.html
Copyright © 2020-2023  润新知