使用Flask开发简单接口(3)--引入MySQL
前言
前面的两篇文章中,我们已经学习了通过Flask开发GET和POST请求接口,但一直没有实现操作数据库,那么我们今天的目的,就是学习如何将MySQL数据库运用到当前的接口项目中。
本人环境:Python 3.7.0 、MySQL 5.7
Flask操作MySQL的2种方式
一般情况,Flask操作MySQL比较常见的方式有2种:SQLAlchemy操作 和 SQL操作 。通过SQLAlchemy操作时,因为大多是通过数据库对象来操作,所以不需要写多少SQL语句,但为了顺便巩固一下SQL知识,在本文章中,我们将采用SQL操作来进行学习。
目前网上的相关文章中,大多数介绍的都是SQLAlchemy操作,SQLAlchemy操作相对也更简单好用一些,因为SQLAlchemy为Python与SQL之间建立了映射,如果使用它可以极大减少SQL语句的编写。
在使用SQL操作方式时,我们需要知道如何利用Python操作MySQL数据库,如果不太清楚的话,可以参考我之前的一篇文章:利用Python操作MySQL数据库
数据库设计
我们创建一个数据库,命名为 flask_demo ,然后新建一个数据表 user ,建表语句如下:
CREATE TABLE `user` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`username` varchar(20) NOT NULL,
`password` varchar(255) NOT NULL,
`role` tinyint(1) NOT NULL,
`sex` tinyint(1) DEFAULT NULL,
`telephone` varchar(255) NOT NULL,
`address` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`),
UNIQUE KEY `telephone` (`telephone`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8;
user表中各字段对应含义如下:
id:用户id号,自增长
username:用户名
password:密码
role:用户角色,0表示管理员用户,1表示普通用户
sex:性别,0表示男性,1表示女性,允许为空
telephone:手机号
address:联系地址,允许为空
user表创建完成后,通过 DESC user 来查看下表结构。
mysql> DESC user;
+-----------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| username | varchar(20) | NO | | NULL | |
| password | varchar(255) | NO | | NULL | |
| role | tinyint(1) | NO | | NULL | |
| sex | tinyint(1) | YES | | NULL | |
| telephone | varchar(255) | NO | UNI | NULL | |
| address | varchar(255) | YES | | NULL | |
+-----------+--------------+------+-----+---------+----------------+
7 rows in set (0.00 sec)
新增配置文件
我们在项目根路径下新建一个包 config ,在该包下存放配置文件 setting.py ,该文件用于配置 MySQL 的服务器地址、端口、用户名及密码、数据库名等参数。
# 服务端口配置
SERVER_PORT = 9999
# MySQL配置
MYSQL_HOST = "192.168.89.128"
MYSQL_PORT = 3306
MYSQL_USER = "root"
MYSQL_PASSWD = "123456"
MYSQL_DB = "flask_demo"
Python操作MySQL
我们在项目根路径下新建一个包 common ,在该包下新建文件 mysql_operate.py ,该文件下封装了Python操作MySQL的代码,后续将通过调用该文件的 db 对象及方法来操作数据库。
import pymysql
from config.setting import MYSQL_HOST,MYSQL_PORT,MYSQL_USER,MYSQL_PASSWD,MYSQL_DB
class MysqlDb():
def __init__(self, host, port, user, passwd, db):
# 建立数据库连接
self.conn = pymysql.connect(
host=host,
port=port,
user=user,
passwd=passwd,
db=db
)
# 通过 cursor() 创建游标对象,并让查询结果以字典格式输出
self.cur = self.conn.cursor(cursor=pymysql.cursors.DictCursor)
def __del__(self): # 对象资源被释放时触发,在对象即将被删除时的最后操作
# 关闭游标
self.cur.close()
# 关闭数据库连接
self.conn.close()
def select_db(self, sql):
"""查询"""
# 检查连接是否断开,如果断开就进行重连
self.conn.ping(reconnect=True)
# 使用 execute() 执行sql
self.cur.execute(sql)
# 使用 fetchall() 获取查询结果
data = self.cur.fetchall()
return data
def execute_db(self, sql):
"""更新/新增/删除"""
try:
# 检查连接是否断开,如果断开就进行重连
self.conn.ping(reconnect=True)
# 使用 execute() 执行sql
self.cur.execute(sql)
# 提交事务
self.conn.commit()
except Exception as e:
print("操作出现错误:{}".format(e))
# 回滚所有更改
self.conn.rollback()
db = MysqlDb(MYSQL_HOST, MYSQL_PORT, MYSQL_USER, MYSQL_PASSWD, MYSQL_DB)
完善GET和POST请求接口
- 获取所有用户信息(GET接口)
@app.route("/users", methods=["GET"])
def get_all_users():
"""获取所有用户信息"""
sql = "SELECT * FROM user"
data = db.select_db(sql)
print("获取所有用户信息 == >> {}".format(data))
return jsonify({"code": "0", "data": data, "msg": "查询成功"})
- 获取某个用户信息(GET接口)
@app.route("/users/<string:username>", methods=["GET"])
def get_user(username):
"""获取某个用户信息"""
sql = "SELECT * FROM user WHERE username = '{}'".format(username)
data = db.select_db(sql)
print("获取 {} 用户信息 == >> {}".format(username, data))
if data:
return jsonify({"code": "0", "data": data, "msg": "查询成功"})
return jsonify({"code": "1004", "msg": "查不到相关用户的信息"})
- 用户注册接口(POST接口)
@app.route("/register", methods=['POST'])
def user_register():
"""用户注册"""
username = request.json.get("username").strip() # 用户名
password = request.json.get("password").strip() # 密码
sex = request.json.get("sex", "0").strip() # 性别,默认为0(男性)
telephone = request.json.get("telephone", "").strip() # 手机号,默认为空串
address = request.json.get("address", "").strip() # 地址,默认为空串
if username and password and telephone:
sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
res1 = db.select_db(sql1)
print("查询到用户名 ==>> {}".format(res1))
sql2 = "SELECT telephone FROM user WHERE telephone = '{}'".format(telephone)
res2 = db.select_db(sql2)
print("查询到手机号 ==>> {}".format(res2))
if res1:
return jsonify({"code": 2002, "msg": "用户名已存在,注册失败!!!"})
elif not (sex == "0" or sex == "1"):
return jsonify({"code": 2003, "msg": "输入的性别只能是 0(男) 或 1(女)!!!"})
elif not (len(telephone) == 11 and re.match("^1[3,5,7,8]\d{9}$", telephone)):
return jsonify({"code": 2004, "msg": "手机号格式不正确!!!"})
elif res2:
return jsonify({"code": 2005, "msg": "手机号已被注册!!!"})
else:
sql3 = "INSERT INTO user(username, password, role, sex, telephone, address) " \
"VALUES('{}', '{}', '1', '{}', '{}', '{}')".format(username, password, sex, telephone, address)
db.execute_db(sql3)
print("新增用户信息 ==>> {}".format(sql3))
return jsonify({"code": 0, "msg": "恭喜,注册成功!"})
else:
return jsonify({"code": 2001, "msg": "用户名/密码/手机号不能为空,请检查!!!"})
在这里,我们实现用户注册的时候,设置只能注册 role 字段值为 1 的普通用户,不允许直接注册管理员用户。相关的接口返回码和请求场景如下:
| 接口返回码 | 请求场景 |
|---|---|
| 0 | 请求参数正确,注册成功 |
| 2001 | 请求参数中,用户名/密码/手机号,任一参数为空 |
| 2002 | 请求参数中,用户名已被其他人注册使用 |
| 2003 | 请求参数中, sex 性别字段值不是 0 或 1 |
| 2004 | 请求参数中,手机号格式不正确 |
| 2005 | 请求参数中,手机号已被其他人注册使用 |
可参考如下进行用户注册接口请求:
请求方式:POST
请求地址:http://127.0.0.1:5000/register
请求头:
Content-Type: application/json
Body:{"username": "wintest5", "password": "123456", "sex": "1", "telephone":"13500010005", "address": "上海市黄浦区"}

- 用户登录接口(POST接口)
@app.route("/login", methods=['POST'])
def user_login():
"""用户登录"""
username = request.values.get("username").strip()
password = request.values.get("password").strip()
if username and password:
sql1 = "SELECT username FROM user WHERE username = '{}'".format(username)
res1 = db.select_db(sql1)
print("查询到用户名 ==>> {}".format(res1))
if not res1:
return jsonify({"code": 1003, "msg": "用户名不存在!!!"})
sql2 = "SELECT * FROM user WHERE username = '{}' and password = '{}'".format(username, password)
res2 = db.select_db(sql2)
print("获取 {} 用户信息 == >> {}".format(username, res2))
if res2:
return jsonify({"code": 0, "msg": "恭喜,登录成功!"})
return jsonify({"code": 1002, "msg": "用户名或密码错误!!!"})
else:
return jsonify({"code": 1001, "msg": "用户名或密码不能为空!!!"})
相关的接口返回码和请求场景如下:
| 接口返回码 | 请求场景 |
|---|---|
| 0 | 用户名和密码正确,登录成功 |
| 1001 | 请求参数中,用户名或密码为空 |
| 1002 | 请求参数中,用户名正确,密码错误 |
| 1003 | 请求参数中,使用了未注册的用户名 |
可参考如下进行用户登录接口请求:
请求方式:POST
请求地址:http://127.0.0.1:5000/login
请求头:
Content-Type: application/x-www-form-urlencoded
Body:username=wintest&password=123456

将项目在服务器部署
- app.run() 启动应用时配置参数
在Flask中,我们通过 app.run() 启动应用时,可以配置一些参数,比如可以配置如下:
from config.setting import SERVER_PORT
if __name__ == '__main__':
# host为主机ip地址,port指定访问端口号,debug=True设置调试模式打开
app.run(host="0.0.0.0", port=SERVER_PORT, debug=True)
上面代码中,host需设置为 0.0.0.0,这样才能在外网进行访问,比如我们在Linux下部署项目,如果想在Windows中进行请求访问,那么就需要设置为 0.0.0.0。
- 将项目根路径加入环境变量
我们把项目根路径下的 app.py 当做该项目的应用启动入口文件,那么就需要将项目的根路径临时加入到环境变量中,否则启动应用时可能会提示找不到相关模块,具体配置如下:
import os, sys
from config.setting import SERVER_PORT
from api.user import app
# 项目根路径
BASE_PATH = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, BASE_PATH) # 将项目根路径临时加入环境变量,程序退出后失效
if __name__ == '__main__':
# host为主机ip地址,port指定访问端口号,debug=True设置调试模式打开
app.run(host="0.0.0.0", port=SERVER_PORT, debug=True)
- 命令行启动应用
我们这个项目的启动,只需要一行命令就可以搞定,以Linux下后台运行方式启动为例,命令如下:
# /root/flaskDemo/app.py表示项目根路径下的app.py启动入口文件路径
# /root/flaskDemo/flaskDemo.log表示输出的日志文件路径
nohup python3 /root/flaskDemo/app.py >/root/flaskDemo/flaskDemo.log 2>&1 &

OK,通过以上内容,我们已经成功将MySQL引入到我们的接口项目中,并可以成功进行接口请求,相关代码已上传到GitHub,大家有兴趣的可以基于此进行简单部署及开展接口测试。
GitHub源码地址:https://github.com/wintests/flaskDemo
使用Flask开发简单接口(3)--引入MySQL的更多相关文章
- 使用Flask开发简单接口(2)--POST请求接口
今天我们继续学习如何使用Flask开发POST接口:用户注册接口和用户登录接口. request接收参数 当我们在页面发出一个POST请求,请求传到服务器时,需要如何拿到当前请求的数据呢?在Flask ...
- 使用Flask开发简单接口(1)--GET请求接口
前言 很多想学习接口测试的同学,可能在最开始的时候,常常会因没有可以练习的项目而苦恼,毕竟网上可以练习的接口项目不多,有些可能太简单了,有些可能又太复杂了,或者是网上一些免费接口请求次数有限制,最终导 ...
- 使用Flask开发简单接口(4)--借助Redis实现token验证
前言 在之前我们已开发了几个接口,并且可以正常使用,那么今天我们将继续完善一下.我们注意到之前的接口,都是不需要进行任何验证就可以使用的,其实我们可以使用 token ,比如设置在修改或删除用户信息的 ...
- 使用Flask开发简单接口(5)--数据加密处理
前言 在之前开发的接口中,我们设计把用户信息存储到数据库时,没有对数据进行加密处理,为了提高下安全性,我们今天就学习下,如何对用户数据进行加密加盐处理. MD5加密加盐 MD5加密 MD5是常用的一种 ...
- 使用Flask开发简单接口
作为测试人员,在工作或者学习的过程中,有时会没有可以调用的现成的接口,导致我们的代码没法调试跑通的情况. 这时,我们使用python中的web框架Flask就可以很方便的编写简单的接口,用于调用或调试 ...
- 使用Django开发简单接口:文章增删改查
目录 1.一些准备工作 安装django 创建django项目 创建博客应用(app) 2.models.py 3.django admin 登录 创建超级用户 4.修改urls.py 5.新增文章接 ...
- 在线支付接口之PHP支付宝接口开发简单介绍
php100:92:在线支付接口之PHP支付宝接口开发 支付接口一般是第三方提供的代收款.付款的平台,可以通过支付接口帮助企业或个人利用一切可以使用的支付方式.常见支付平台:支付宝.快钱.云网支付.财 ...
- Java开发笔记(五十八)简单接口及其实现
前面介绍了抽象方法及抽象类的用法,看似解决了不确定行为的方法定义,既然叫唤动作允许声明为抽象方法,那么飞翔.游泳也能声明为抽象方法,并且鸡类涵盖的物种不够多,最好把这些行为动作扩展到鸟类这个群体,于是 ...
- Flask开发系列之初体验
Flask开发初探 介绍 在日常开发中,如果需要开发一个小型应用或者Web接口,一般我是极力推崇Flask的,主要是因为其简洁.扩展性高. 从这篇文章开始,我会写一个关于Flask的系列文章,通过多个 ...
随机推荐
- 脱壳实践之寻找OEP——两次内存断点法
0x00 前言 对于加壳程序第一件事就是要找到OEP(oringinal Entry point),由于加壳的缘故,当PE文件载入OD或者其他调试软件时进入的的往往是壳程序的入口地址.所以要进行逆 ...
- day42 io模型
目录 一.io模型简介 二.阻塞io阻塞IO模型图.png 三.非阻塞io 四.io多路复用 五.异步io 一.io模型简介 Stevens在文章中一共比较了五种IO Model: blocking ...
- Vue 的响应式原理中 Object.defineProperty 有什么缺陷?
Object.defineProperty只能劫持对象的属性,从而需要对每个对象,每个属性进行遍历,如果,属性值是对象,还需要深度遍历.Proxy可以劫持整个对象,并返回一个新的对象. Proxy不仅 ...
- Linux系统中到底应该怎么理解系统的平均负载
02 | 基础篇:到底应该怎么理解“平均负载”? 每次发现系统变慢时,我们通常做的第一件事,就是执行 top 或者 uptime 命令,来了解系统的负载情况.比如像下面这样,我在命令行里输入了 upt ...
- java 数据结构(四):java常用类四 比较器以及其他类
比较器 1.Java比较器的使用背景: Java中的对象,正常情况下,只能进行比较:== 或 != .不能使用 > 或 < 的但是在开发场景中,我们需要对多个对象进行排序,言外之意,就需要 ...
- java 基本语法(九) 数组(二) 一维数组
1.一维数组的声明与初始化 正确的方式: int num;//声明 num = 10;//初始化 int id = 1001;//声明 + 初始化 int[] ids;//声明 //1.1 静态初始化 ...
- 计算机网络学习socket--day3
1.REUSEADDR(地址重复利用) 1.REUSEADDR解决服务器关闭后重新绑定地址,在day3中知道服务器端必须绑定地址 2.服务器端尽可能使用REUSEADDR 3.在绑定之前尽可能调用se ...
- OSCP Learning Notes - Capstone(1)
Kioptrix Level 1.1 Walkthrough Preparation: Download the virtual machine from the following website ...
- p44_IP数据包格式
一.IP数据报格式 二.IP分片 数据链路层每帧可封装数据有上限,IP数据超过的要分片. 标识:同一数据报的分片使用同一标识 标志: 片偏移(13bit):用于还原数据报顺序,指出某片在原分组1中的相 ...
- STL源码剖析:算法
启 算法,问题之解法也 算法好坏的衡量标准:时间和空间,单位是对数.一次.二次.三次等 算法中处理的数据,输入方式都是左闭又开,类型就迭代器, 如:[first, last) STL中提供了很多算法, ...