测试平台系列(79) 编写Redis配置功能(下)
大家好~我是
米洛!
我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持。
欢迎关注我的公众号测试开发坑货,获取最新文章教程!
回顾
上一节我们提出了优化Dao逻辑的想法,那今天就试着来兑现之,并运用到Redis配置管理的开发中去。
初步构思list方法
我们在dao/init.py新建类: Mapper,以后所有的dao类都继承自它。
想想list需要什么,一般需要,字段,参数, 是like还是等于这3个重要的信息。
明白这个以后,我们的伪代码就好编写了:
# 1. 获取session
async with async_session() as session:
condition = [model.deleted_at == 0]
# 2. 根据参数里的字段,字段值构造查询条件
DatabaseHelper.where(字段,字段值,condition)
# 3. 查询出结果,后续与原来的方式一致,就不写了
可以看到,这边除了需要上面的3个信息以外,还需要try去写入日志,也就是说需要我们平时经常创建的log成员变量,还需要model这个类,否则你不知道改的是什么表。
思考
我们平时的参数,都是key-value的形式,一旦value不为空,那么说明我们要根据这个条件来查询。
而model和log,我们可以通过类的装饰器,由子类传递给父类(这里会用到setattr和getattr)
class Mapper(object):
log = None
model = None
@classmethod
async def list_data(cls, **kwargs):
try:
async with async_session() as session:
# 构造查询条件,默认是数据未被删除
condition = [getattr(cls.model, "deleted_at") == 0]
# 遍历参数,当参数不为None的时候传递
for k, v in kwargs.items():
# 判断是否是like的情况 TODO: 这里没支持in查询
like = v is not None and len(v) > 2 and v.startswith("%") and v.endswith("%")
# 如果是like模式,则使用Model.字段.like 否则用 Model.字段 等于
DatabaseHelper.where(v, getattr(cls.model, k).like(v) if like else getattr(cls.model, k) == v,
condition)
result = await session.execute(select(cls.model).where(*condition))
return result.scalars().all()
except Exception as e:
# 这边调用cls本身的log参数,写入日志+抛出异常
cls.log.error(f"获取{cls.model}列表失败, error: {e}")
raise Exception(f"获取数据失败")
注释写的比较详细,由于现在字段是个变量,所以我们不能用model.字段来取值,所以取而代之的是getattr(model, 字段)。不熟悉的朋友可以去搜索下getattr。
这样,一个粗略的list方法就写好了,但是这个是不带分页的,所以我们还需要补充一个分页的模式,其实也很简单。
@classmethod
async def list_data_with_pagination(cls, page, size, **kwargs):
try:
async with async_session() as session:
condition = [getattr(cls.model, "deleted_at") == 0]
for k, v in kwargs.items():
like = v is not None and len(v) > 2 and v.startswith("%") and v.endswith("%")
sql = DatabaseHelper.where(v, getattr(cls.model, k).like(v) if like else getattr(cls.model, k) == v,
condition)
return await DatabaseHelper.pagination(page, size, session, sql)
except Exception as e:
cls.log.error(f"获取{cls.model}列表失败, error: {e}")
raise Exception(f"获取数据失败")
基本上长的差不多,只是最后返回那里,调用了pagination相关方法。
看看dao装饰器

我们很坏,把这个装饰器套到子类上,并把model和log传给父类。毕竟方法都是在调用父类的方法,父类无法直接拿到子类的数据。

这样就避免了在调用list方法的时候,还需要传入model和log的尴尬情况。
完善其他方法
list搞定以后,其他的还会远吗?但还真的好像还有点问题,因为我们一般会有一些重名判断,但没关系,我们可以编写一个query方法。
@classmethod
def query_wrapper(cls, **kwargs):
condition = [getattr(cls.model, "deleted_at") == 0]
# 遍历参数,当参数不为None的时候传递
for k, v in kwargs.items():
# 判断是否是like的情况 TODO: 这里没支持in查询
like = v is not None and len(v) > 2 and v.startswith("%") and v.endswith("%")
# 如果是like模式,则使用Model.字段.like 否则用 Model.字段 等于
DatabaseHelper.where(v, getattr(cls.model, k).like(v) if like else getattr(cls.model, k) == v,
condition)
return select(cls.model).where(*condition)
@classmethod
async def query_record(cls, **kwargs):
try:
async with async_session() as session:
sql = cls.query_wrapper(**kwargs)
result = await session.execute(sql)
return result.scalars().first()
except Exception as e:
cls.log.error(f"查询{cls.model}失败, error: {e}")
raise Exception(f"查询数据失败")
由于查询方法太过于通用,所以抽成了query_wrapper方法。
- 正常编写insert接口
@classmethod
async def insert_record(cls, model):
try:
async with async_session() as session:
async with session.begin():
session.add(model)
await session.flush()
session.expunge(model)
return model
except Exception as e:
cls.log.error(f"添加{cls.model}记录失败, error: {e}")
raise Exception(f"添加记录失败")
这边返回了model,如果不需要也可以不用,但咱还是给返回。
- insert接口层

和以前一样,先查,如果没有再关掉。
但这样会产生2个session,开->关->开->关
但也解耦了查询和插入2个操作。
- 编写删除和修改方法
@classmethod
async def update_record_by_id(cls, user, model, not_null=False):
try:
async with async_session() as session:
async with session.begin():
query = cls.query_wrapper(id=model.id)
result = await session.execute(query)
original = result.scalars().first()
if original is None:
raise Exception("记录不存在")
DatabaseHelper.update_model(original, model, user, not_null)
await session.flush()
session.expunge(original)
return original
except Exception as e:
cls.log.error(f"更新{cls.model}记录失败, error: {e}")
raise Exception(f"更新记录失败")
@classmethod
async def delete_record_by_id(cls, user, id):
"""
逻辑删除
:param user:
:param id:
:return:
"""
try:
async with async_session() as session:
async with session.begin():
query = cls.query_wrapper(id=id)
result = await session.execute(query)
original = result.scalars().first()
if original is None:
raise Exception("记录不存在")
DatabaseHelper.delete_model(original, user)
except Exception as e:
cls.log.error(f"删除{cls.model}记录失败, error: {e}")
raise Exception(f"删除记录失败")
@classmethod
async def delete_by_id(cls, id):
"""
物理删除
:param id:
:return:
"""
try:
async with async_session() as session:
async with session.begin():
query = cls.query_wrapper(id=id)
result = await session.execute(query)
original = result.scalars().first()
if original is None:
raise Exception("记录不存在")
session.delete(original)
except Exception as e:
cls.log.error(f"逻辑删除{cls.model}记录失败, error: {e}")
raise Exception(f"删除记录失败")
删除这边支持了物理删除和逻辑删除,当然我们一般是用软删除。
完善其他接口

可以看到删除和修改和以前是差不多的(也是内部进行数据是否存在判断),这些步骤做完。redis的管理工作就可以顺利进行了,接着我们需要为之编写页面咯!
由于是很基础的表格页面,所以我们不赘述。下一节我们会利用配置的redis连接编写redisManager,管理我们的连接数据,为之后在线执行redis以及将它作为前置条件打下基础。
测试平台系列(79) 编写Redis配置功能(下)的更多相关文章
- 测试平台系列(81) 编写在线执行Redis功能
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们牛刀小试,编写了 ...
- 测试平台系列(80) 封装Redis客户端
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们编写了Redis ...
- 测试平台系列(85) 把redis运用到实战中
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们让支持了前置条件 ...
- 测试平台系列(90) 编写oss客户端
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持. 欢迎关注我的公众号米洛的测开日记,获取最新文章教程! 回顾 上一节我们编写了在线执行测试 ...
- 测试平台系列(91) 编写oss管理页面
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持. 欢迎关注我的公众号米洛的测开日记,获取最新文章教程! 回顾 上一节我们编写好了oss相关 ...
- 测试平台系列(83) 前置条件支持Redis语句
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上节我们打了个野,解决了一 ...
- 测试平台系列(72) 了解ApScheduler基本用法
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们调研了一下市面上 ...
- 测试平台系列(82) 解决APScheduler重复执行的问题
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的完整教程,希望大家多多支持. 欢迎关注我的公众号测试开发坑货,获取最新文章教程! 回顾 上一节我们编写了在线执行R ...
- 测试平台系列(92) 让http请求支持文件上传
大家好~我是米洛! 我正在从0到1打造一个开源的接口测试平台, 也在编写一套与之对应的教程,希望大家多多支持. 欢迎关注我的公众号米洛的测开日记,获取最新文章教程! 回顾 上一节呢,我们编写了oss的 ...
随机推荐
- 理解ASP.NET Core - 配置(Configuration)
注:本文隶属于<理解ASP.NET Core>系列文章,请查看置顶博客或点击此处查看全文目录 配置提供程序 在.NET中,配置是通过多种配置提供程序来提供的,包括以下几种: 文件配置提供程 ...
- Blazor Webassembly多标签页开发
最近准备用Blazor Webassembly做后台开发要用到多标签页,找了半天发现绝大多数都是Blazor Server的多标签没有Webassembly.没办法只能自己想办法造轮子了. 查了许多资 ...
- 《面试八股文》之 JVM 20卷
微信公众号:moon聊技术 关注选择" 星标 ", 重磅干货,第一 时间送达! [如果你觉得文章对你有帮助,欢迎关注,在看,点赞,转发] 大家好,我是 moon. <面试八股 ...
- C++核心编程 4 类和对象-对象的初始化和清理
构造函数和析构函数 对象的初始化和清理工作是两个非常重要的安全问题,一个对象或者变量没有初始状态,对其使用结果是未知的,同样,使用完一个对象或变量,没有及时清理,也会造成一定的安全问题.C++利用了构 ...
- SQL 居然还能在 Apache ShardingSphere 上实现这些功能?
在去年 10 月 5.0.0-alpha 版本发布之后,Apache ShardingSphere 经历了长达 8 个多月的持续开发与优化,终于在 6 月 25 日正式迎来了 5.0.0-beta 版 ...
- SpringBoot-thymeleaf-静态资源引入和接管
引入前端 templates下放html页面 static下放css.js.image等静态资源 添加thymeleaf命名空间 <html lang="en" xmlns: ...
- 自动化运维利器Ansible要点汇总
由于大部分互联网公司服务器环境复杂,线上线下环境.测试正式环境.分区环境.客户项目环境等造成每个应用都要重新部署,而且服务器数量少则几十台,多则千台,若手工一台台部署效率低下,且容易出错,不利后期运维 ...
- Java中的函数式编程(三)lambda表达式
写在前面 lambda表达式是一个匿名函数.在Java 8中,它和函数式接口一起,共同构建了函数式编程的框架. lambda表达式乍看像是匿名内部类的一种语法糖,但实际上,它们是两种本质不同的事物 ...
- 初始HTML04
HTML 列表标签 无序列表 默认用实心圆点标识列表项 1 <ul> 2 <li>list item 列表项</li> 3 <li>list item ...
- “介绍一下自己吧”——记2020BUAA软工团队介绍和采访
写在前面 项目 内容 这个作业属于哪个课程 2020春季计算机学院软件工程(罗杰 任建) 这个作业的要求在哪里 团队作业-团队介绍和采访 团队介绍 团队名称 我们是 BUAA软软软件工程小队 ,简称 ...