测试需求平台7-产品管理服务接口一篇搞定

本文介绍了如何使用Vue3.0和FlaskAPI重构TPM提测平台,重点讲解了产品管理模块的接口服务实现,包括封装数据连接、添加、修改和删除接口,以及使用with语句确保数据库操作的正确性。
摘要由CSDN通过智能技术生成

✍此系列为整理分享已完结入门搭建《TPM提测平台》系列的迭代版,拥抱Vue3.0将前端框架替换成字节最新开源的arco.design,其中约60%重构和20%新增内容,定位为从 0-1手把手实现简单的测试平台开发教程,内容将囊括基础、扩展和实战,由浅入深带你实现测试开发岗位中平台工具技术能力入门和提升。

基于前几篇有关Flask API使用教程、Blueprint路由优化、数据持久化PyMySQL使用的知识内容,本篇就可以很轻松的实现《测试需求平台》中产品模块管理所需要的所有接口服务了。

1.封装数据连接

在正式过实现接口服务之前,我们需要先封装下之前做数据连接操作写在外边的对象代码,因为多方法中如增、改、删使用完后会关闭数据库连接,所以不能一次声明到处使用,我们需要在每次接口请求处理业务前,进行新的数据库初始化,保证数据库连接实例可用。

# 数据库连接方法
def connectDB():
    connection = pymysql.connect(host='127.0.0.1',   
                             user='mrzcode',
                             password='mrzcode',
                             database='TPMStore',
                             charset='utf8mb4', 
                             cursorclass=pymysql.cursors.DictCursor) 
    # 返回新数据库连接对象
    return connection

最简单的方式就是提取出一个公共方法,每个接口方法实现的时候只需调用重新实例化即可,这个定义就直接在product.py 顶部实现。

当然对于数据管理还可以提取配置文件、使用连接池等方式进一步优化,不过学习总要有个循序渐进的过程,当前先卖个关子,后续会详细讲到。

2. 产品管理接口

2.1 添加接口

基于之前实现的产品查询接口类 product.py 实现产品信息添加接口,基础关键定义如下:

  • methods 定义为POST请求
  • flask request模块的get_data()获取body
  • json 请求处理请求的JSON格式数据

新增依赖引用,其中json是一种轻量级的数据交换格式。

from flask import request
import json

在实现产品新增信息落库之前要增加一个查询判断是否已经存在的逻辑,需求上定义keyCode是关键词,名称可以相同不做特殊处理,如果重复给出提示,code 定义20001,代码中千万不要忘记上节数据操作的commit动作。

# [POST方法]实现新建数据的数据库插入
@app_product.route("/api/product/create",methods=['POST'])
def product_create():
    # 初始化数据库链接
    connection = connectDB()
    # 定义默认返回结构体
    resp_data = {
        "code": 20000,
        "message": "success",
        "data": []
    }

    # 获取请求传递json body
    body = request.get_data()
    body = json.loads(body)

    with connection:
        # 先做个查询,判断keyCode是否重复(这里的关键词最初定义为唯一项目编号或者为服务的应用名)
        with connection.cursor() as cursor:
            select = "SELECT * FROM `products` WHERE `keyCode`=%s"
            cursor.execute(select, (body["keyCode"],))
            result = cursor.fetchall()

        # 有数据说明存在相同值,封装提示直接返回
        if len(result) > 0:
            resp_data["code"] = 20001
            resp_data["message"] = "唯一编码keyCode已存在"
            return resp_data

        with connection.cursor() as cursor:
            # 拼接插入语句,并用参数化%s构造防止基本的SQL注入
            # 其中id为自增,插入数据默认数据设置的当前时间
            sql = "INSERT INTO `products` (`keyCode`,`title`,`desc`,`operator`) VALUES (%s,%s,%s,%s)"
            cursor.execute(sql, (body["keyCode"], body["title"], body["desc"], body["operator"]))
            # 提交执行保存插入数据
            connection.commit()

        # 按返回模版格式进行json结果返回
        return resp_data

以上编写完成再次用ide或者命令运行 app.py 启动后端程序,用postman接口测试工具进行请求测试,验证产品新增接口服务两种逻辑情况
1)符合条件请求验证数据正确落库
image.png

2)KeyCode已经存在验证返回提示image.png特别说明一下,本系列练手项目不会过多做比如边界值、接口参数缺失等这类信息,毕竟前后端都一个人开发,配合约定有一端处理不出现上述情况即可,不过如果在实际工作项目中多人开发的时候,后端的接口相关的必要验证处理还是建议写的。

2.2 修改接口

产品信息修改与插入的代码逻辑几乎一样,只是请求Body需要而外带过来插入自动生成的ID,并将语句换成了UPDATE语法。

# [POST方法]根据项目ID进行信息更新
@app_product.route("/api/product/update",methods=['POST'])
def product_update():

    # 按返回模版格式进行json结果返回
    resp_data = {
        "code": 20000,
        "message": "success",
        "data": []
    }

    # 获取请求传递json
    body = request.get_data()
    body = json.loads(body)
    # 初始化数据库链接
    connection = connectDB()

    with connection:
        with connection.cursor() as cursor:
            # 查询需要过滤状态为有效的
            select = "SELECT * FROM `products` WHERE `keyCode`=%s AND `status`=0"
            cursor.execute(select, (body["keyCode"],))
            result = cursor.fetchall()

            # 有数据并且不等于本身则为重复,封装提示直接返回
            if len(result) > 0 and result[0]["id"] != body["id"]:
                resp_data["code"] = 20001
                resp_data["message"] = "唯一编码keyCode已存在"
                return resp_data

        # 如果没有重复,定义新的链接,进行更新操作
        with connection.cursor() as cursor:
            # 拼接更新语句,并用参数化%s构造防止基本的SQL注入
            # 条件为id,更新时间用数据库NOW()获取当前时间
            sql = "UPDATE `products` SET `keyCode`=%s, `title`=%s,`desc`=%s,`operator`=%s, `update`= NOW() WHERE id=%s"
            cursor.execute(sql, (body["keyCode"], body["title"], body["desc"], body["operator"], body['id']))
            # 提交执行保存更新数据
            connection.commit()

        return resp_data

修改逻辑中也需要对KeyCode做重复校验,如果需求上定义KeyCode不可以修改,那么只需要前端在修改的时候处理成置灰不可更改就行。另外查询的时候拿去数据我用了是fetchall()做的循环判定,这里可以简化为fetchone() ,毕竟在插入的时候已经做了防重限制,正常情况下只会出现空或一条数据。

同样进行代码逻辑的测试,这里首先演示上说的没做参数校验是啥情况的返回,明显的代码错误在body[“id”]获取的时候异常,直接返回了框架Traceback 错误。

image.png此处是独立的更新接口,因为id是修改操作where关键,笔者是推荐先做一步id参数是否为空的校验,如果是你应该怎么优化呢?提示可以使用 if ('key' not in body): 做逻辑判断。

对于修改这里只验证下正确修改的情况image.png

2.3 删除接口

对于产品列表的删除操作,可以通过硬删除和软删除来实现,前者就是真正DELETE,后者是对其表增加一个状态字段,标记某状态为删除状态,在查询接口中需要通过条件查询排除此状态。

硬删除接口

按照标准的RefAPI,通过定义methods = delete方法定义请求接口,参数只需要对应数据的id,于此同时因为id是删除的操作唯一条件,所以代码逻辑中有必要增一项非空判断。

# [DELETE方法]根据id实际删除项目信息
@app_product.route("/api/product/delete", methods=['DELETE'])
def product_delete():
    # 返回的reponse
    resp_data = {
        "code": 20000,
        "message": "success",
        "data": []
    }
    
    # 通过params 获取id
    ID = request.args.get('id')
    
    # 做个参数必填校验
    if ID is None:
        resp_data["code"] = 20002
        resp_data["message"] = "请求id参数为空"
        return resp_data
    
    # 重新链接数据库
    connection = connectDB()
    with connection.cursor() as cursor:
        sql = "DELETE from `products` where id=%s"
        cursor.execute(sql, ID)
        connection.commit()
    return resp_data
软删除接口

在通常的业务操作中数据都不是真的删除的,尤其像产品/项目这种会有下游依赖的数据,一般做法都是表数据增加对应的状态字段,用数字或者字符表示状态,所需要做的操作就是“删除”触发的是更新操作,在需求交互上我们叫“停用”更为合适一些,这也就是所谓的软删除,仅标记状态不做实际数据删除。

1)先要对products表增加一个状态字段,执行中执行修改命令,或使用IDE直接添加均可。

alter table products add status int default 0 not null comment '状态有效0,无效1' after `desc`;

2)定义的新/api/product/remove接口名,参考修改和硬删除代码实现软删除接口

# [POST方法]根据id更新状态项目状态,做软删除
@app_product.route("/api/product/remove", methods=['POST'])
def product_remove():
    # 返回的reponse
    resp_data = {
        "code": 20000,
        "message": "success",
        "data": []
    }
    ID = request.args.get('id')

    # 做个参数必填校验
    if ID is None:
        resp_data["code"] = 20002
        resp_data["message"] = "请求id参数为空"
        return resp_data

    # 重新链接数据库
    connection = connectDB()

    # 更改操作
    with connection.cursor() as cursor:
        # 状态默认正常状态为0,删除状态为1
        # alter table products add status int default 0 not null comment '状态有效0,无效0' after `desc`;
        sql = "UPDATE `products` SET `status`=1 WHERE id=%s"
        cursor.execute(sql, ID)
        connection.commit()

    return resp_data

以上两个接口就不做测试演示了,大家自行做下验证测试。

3.Python with语句

扩展了解一个python知识点,从上边的所有代码中可以看到,通篇数据操作的没有进行db.close()操作,而是用了with as ,它的基本思想是with所求值对象必须有一个enter()方法,一个exit()方法。应用到数据库操作实例中就是实现了执行退出后关闭具柄,python最常见用语文件处理,举个对比实例:

# 带有异常捕获文件打开和关闭
file = open("/source/qitest.txt")
try:
    data = file.read()
finally:
    file.close()   

可优化为如下优雅代码,它帮助我们处理了异常和忘记关闭文件流两种情况

with open("/source/qitest.txt") as file:
    data = file.read()

以上内容通过串联前几篇的知识内容,实现了产品管理的 接口,并且都是通过数据的方式存储值,下一篇讲基础后端服务接口实现其产品管理的基础交互,你将学到很多新的组件。

最后大奇再啰嗦一句给个建议,文章中给出的大量源代码,希望如果你还是处于语言学习基础阶段,实战的代码最好只是作为参考,真正的要自己一行行敲出来,不要直接拷贝,否则你不会记住多少,也不会遇到问题,更不会锻炼出解决问题的能力。学习的路上方法资料可以参考,但想要有收获是没有捷径的,一起共勉。

  • 27
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mega Qi

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值