Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试

文章目录

  • 一、前置准备
    • 1.1 创建数据表
    • 1.2 修改 Postman 的请求头
  • 二、具体实现
    • 2.1 utils.py
    • 2.2 mysql.py
    • 2.3 models.py
    • 2.4 entity.py
    • 2.5 app.py
  • 三、Postman 测试接口
    • 3.1 测试访问接口
    • 3.2 测试注册接口
      • 3.2.1 参数为空
      • 3.2.2 缺少参数
      • 3.2.3 用户名重复
      • 3.2.4 注册成功
    • 3.3 测试登录接口
      • 3.3.1 缺少参数
      • 3.3.2 用户名或密码错误
      • 3.3.3 登录成功
    • 3.4 测试用户注销接口
      • 3.4.1 操作成功
      • 3.4.2 暂未登录
    • 3.4 测试用户状态验证接口
      • 3.4.2 暂未登录
      • 3.4.1 验证通过
    • 3.5 测试查询用户数据的接口
      • 3.5.1 测试查询所有用户接口
      • 3.5.2 测试查询指定ID用户的接口


Flask 是一个使用 Python 编写的轻量级 Web 应用程序框架。接下来以初学者的角度来编写后端的接口,不涉及前端代码,即没有用到 Flask 的模板渲染。

运行环境:

  • windows11
  • PyCharm 专业版 2021.3
  • MySQL 5.7.36
  • Navicat 15 数据库管理工具
  • Postman 接口请求工具
  • Anaconda 3
  • python 3.8
  • flask 2.2.0
  • flask_sqlalchemy 2.5.1 ,flask 框架支持ORM 数据持久化的库

案例的文件结构:
Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第1张图片

一、前置准备

1.1 创建数据表

本次小案例,只用到一张用户表 sys_user

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第2张图片

建表的 MySQL 语句:

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for sys_user
-- ----------------------------
DROP TABLE IF EXISTS `sys_user`;
CREATE TABLE `sys_user`  (
  `user_id` int(11) NOT NULL AUTO_INCREMENT,
  `user_name` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  `user_password` varchar(255) CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`user_id`) USING BTREE,
  UNIQUE INDEX `user_name`(`user_name`) USING BTREE COMMENT '用户名称不可重复'
) ENGINE = InnoDB AUTO_INCREMENT = 8 CHARACTER SET = utf8mb4 COLLATE = utf8mb4_general_ci ROW_FORMAT = Dynamic;

-- ----------------------------
-- Records of sys_user
-- ----------------------------
INSERT INTO `sys_user` VALUES (1, '小王', '123456');
INSERT INTO `sys_user` VALUES (2, '小绿', '123456');
INSERT INTO `sys_user` VALUES (3, 'uni', '123456');

SET FOREIGN_KEY_CHECKS = 1;

1.2 修改 Postman 的请求头

最后在进行接口测试时,需要通过 JSON 传值,这里需要指定为 application/json; 的格式,为避免出现中文乱码,最好加上charset=utf8
Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第3张图片

Content-Type = application/json;charset=utf8

二、具体实现

2.1 utils.py

Flask 框架在处理请求后,返回的数据必须是可转化为JSON的类型,即字典类型。此工具文件中的方法支持将列表里的所有 User 对象转化到 dict 字典中,其中的 key 为下标,value 则为 Use对象调用 dict() 的结果,这个方法是自定义的,待会在 models.py 里会说明。

"""
    将列表里的对象逐一转化为字典, 对象需提供 dict 方法
"""
def model_list_to_dict(modelList: list):
    result = {}
    for index, model in enumerate(modelList):
        result.update({index: model.dict()})
    return result

2.2 mysql.py

该脚本只是创建了 SQLAlchemy() 对象,至于为什么将它单独放在这个文件里,是因为后面的 models.py 和 app.py 都将用到它,这里类似单例模式的设计,是为了防止重复创建 SQLAlchemy() 对象

from flask_sqlalchemy import SQLAlchemy
db = SQLAlchemy()

2.3 models.py

Flask 框架中 flask_sqlalchemy 库 支持数据库的交互,使用前需定义数据库中表的对应类,该类的特点有:

  • 必须继承 SQLAlchemy() 对象中的 Model
  • 必须指定表名,__tablename__
  • 定义字段对应的变量必须是静态变量,且需调用 SQLAlchemy() 对象的 Column 方法

这里的 dict() 方法是我自定义的,个人觉得这样比较方便,在 Flask 返回数据时必须是能转化成 JSON 的字符串,同时在输出时也方便查看,相当于 Java 的 toString

from mysql import db

"""--------------------------------------
            定义 MySQL 用户的映射类
-----------------------------------------"""

class User(db.Model):
    __tablename__ = "sys_user"
    id = db.Column(db.Integer, name='user_id', primary_key=True)
    name = db.Column(db.String, name='user_name', unique=True)
    password = db.Column(db.String, name='user_password')

    def dict(self):
        return {
            'id': self.id,
            'name': self.name,
            'password': self.password
        }

2.4 entity.py

前后端交互响应类 r ,在接口返回数据时调用,其实直接调用 flask 提供的 jsonify()方法就行,这里自定义一个 r,作用是为了指定默认的参数,比如指定 code = 200,默认为 200 响应代码,表示响应成功。除此之外,我们返回的 r 是继承于 python内置的** dict 字典 **的,支持转化为 JSON 格式的数据。
这种返回的 r 一定会存在 code、msg 和 data 这三个 key,方便前端对接口响应的数据进行判断与处理。
jsonify 是备用的,如果出现报错,再调用 flask 提供的这个方法。

from flask import jsonify
"""
    前后端交互响应类
"""
class r(dict):
    def __init__(self, code=200, msg='空', data=None):
        super().__init__(code=code, msg=msg, data=data)

    def jsonify(self):
        return jsonify(self)

2.5 app.py

app.py 是创建 Flask 实例 以及编写 API 接口的主要实现的文件,这里其实应该可以分为两个文件,由于是初学就暂时不分那么清晰。
代码看起来比较长,但逻辑是很清楚的,先创建 Flask 实例,使用 pymysql 加载 mysql 引擎,通过 Flask 实例对象配置 MySQL 连接的 URL(URL里包含了数据库的账号和密码),使用 @app.route() 标记负责响应请求的类,可以类比 SpringMVC 里的 Controller。

from flask import Flask, request, session
from typing import List
from mysql import db
from models import User
from utils import model_list_to_dict  # 自定义的 utils 工具包
import pymysql
from entity import r

# 创建 Flask 实例
app = Flask(__name__)

"""----------------------------------------
                初始化 Flask 
-------------------------------------------"""
# 初始化数据库
pymysql.install_as_MySQLdb()
# 配置数据库
app.config['SQLALCHEMY_DATABASE_URI'] = "mysql://root:woaini@localhost:3306/flask_test_db"
# 解决中文乱码
app.config['JSON_AS_ASCII'] = False
# 关闭
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
# 设置 session 密钥
app.config['SECRET_KEY'] = 'I LIKE U'
# 初始化数据库
db.init_app(app)


"""----------------------------------------
                API: 初始化
-------------------------------------------"""
@app.route('/', methods=['GET'])
def hello():
    return r(code=200, msg='服务器访问成功!')


"""----------------------------------------
                API: 查询所有用户
-------------------------------------------"""
@app.route('/user', methods=['GET'])
def user_find_all():
    userList: List[User] = User.query.all()
    return r(code=200, msg='用户查询成功', data=model_list_to_dict(userList))


"""----------------------------------------
                API: 根据ID查询指定用户
-------------------------------------------"""
@app.route('/user/', methods=['GET'])
def user_find(user_id):
    user = User.query.get(user_id)
    if user == None:
        return r(code=200, msg='用户不存在')
    else:
        return r(code=200, msg='用户查询成功', data=user.dict())


"""----------------------------------------
                API: 注册用户
-------------------------------------------"""
@app.route('/register', methods=['POST'])
def user_register():
    reqJSONData = request.get_json(silent=True)  # 允许 请求体的 raw 为空
    # 1. 处理请求参数为空
    if not reqJSONData: return r(code=401, msg='注册失败, 请求参数为空')
    username = reqJSONData.get('username')
    password = reqJSONData.get('password')
    # 2. 处理请求参数缺少
    if not all([username, password]):
        return r(code=401, msg='注册失败, 缺少请求参数', )
    # 3. 根据 user_name 字段判断用户是否注册过
    try:
        user = User.query.filter_by(name=username).first()
        if user:
            return r(code=401, msg='注册失败, 用户已存在')
    except Exception as e:
        print(e, '[Error] in [/user] [POST] when select MYSQL user where name=[] .')
        return r(code=402, msg='服务器内部出错')
    # 4. 注册用户到数据库
    user = User(name=username, password=password)
    try:
        db.session.add(user)
        db.session.commit()  # 提交事务
    except Exception as e:
        db.session.rollback()  # 异常时回滚
        print(e, '[Error] in [/user] [POST] when inserting a user into MySQL.')
        return r(code=402, msg='服务器内部出错')
    print('新用户注册成功:  ', user.dict())
    return r(code=200, msg='注册成功', data=user.dict())


"""----------------------------------------
                API: 用户登录
-------------------------------------------"""
@app.route('/login', methods=['POST'])
def user_login():
    reqJSONData = request.get_json(silent=True)  # 允许 请求体的 raw 为空
    # 1. 处理请求参数为空
    if not reqJSONData: return r(code=401, msg='注册失败, 请求参数为空')
    username = reqJSONData.get('username')
    password = reqJSONData.get('password')
    # 2. 处理请求参数缺少
    if not all([username, password]):
        return r(code=401, msg='登录, 缺少请求参数')
    # 3. 验证账号和密码
    user = User.query.filter_by(name=username, password=password).first()
    # 4. 用户不存在, 直接返回
    if not user:
        return r(code=404, msg='用户名或密码错误')
    else:
        # 5. 保存用户状态到 session
        session['user_info'] = user.dict()
        return r(msg='登录成功', data=user.dict())


"""----------------------------------------
                API: 验证用户状态
-------------------------------------------"""
@app.route('/login', methods=['GET'])
def user_check_login():
    userDict = session.get('user_info')
    if not userDict:
        return r(code=401, msg='未登录')
    else:
        return r(msg='用户已登录', data=userDict)


"""----------------------------------------
                API: 注销登录
-------------------------------------------"""
@app.route('/logout', methods=['GET'])
def user_logout():
    userDict = session.get('user_info')
    if not userDict:
        return r(msg='暂未登录')
    session.pop("user_info")
    return r(msg='操作成功', data=userDict)


if __name__ == '__main__':
    app.run(host='localhost', port=8081, debug=True)

三、Postman 测试接口

在 app.py 中的 128 行,设置的端口为 8081,启动 app.py 后访问 localhost:8081

3.1 测试访问接口

[GET]
/ 

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第4张图片

3.2 测试注册接口

注册接口处理了四种不同的情况:1)参数为空;2)缺少参数;3)用户名重复;4)注册成功,接下来逐一测试

[POST]
/register

3.2.1 参数为空

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第5张图片

3.2.2 缺少参数

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第6张图片

3.2.3 用户名重复

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第7张图片

3.2.4 注册成功

根据 MySQL 数据表设计,用户ID字段 user_id 是自动递增的,这里由于我之前测试的时候添加过几条数据,然后又删除了,所以新注册后的用户 ID 变成了之前7的下一个 ,问题不大,能注册就OK
Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第8张图片

3.3 测试登录接口

登录有两种情况:1)缺少参数;2)登录失败;3)登录成功

[POST]
/login

3.3.1 缺少参数

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第9张图片

3.3.2 用户名或密码错误

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第10张图片

3.3.3 登录成功

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第11张图片

3.4 测试用户注销接口

注销有两种情况:1)操作成功;2)暂未登录

[GET]
/logout

3.4.1 操作成功

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第12张图片

3.4.2 暂未登录

注销时若未登录则提示,返回代码依旧为 200,表示操作成功
Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第13张图片

3.4 测试用户状态验证接口

状态验证不需要传参,后端只需要判断 session 里是否存在用户对象就行。

[GET]
/login

3.4.2 暂未登录

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第14张图片

3.4.1 验证通过

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第15张图片

3.5 测试查询用户数据的接口

3.5.1 测试查询所有用户接口

[GET]
/user

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第16张图片

3.5.2 测试查询指定ID用户的接口

查询指定ID用户,有两种可能:1)用户存在;2)用户不存在

[GET]
/user/:id
  • 用户存在

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第17张图片

  • 用户不存在

Python Web 开发 | Flask(一) 简单实现用户注册、登录、注销、查询接口 | 初学者案例 | 简单封装响应数据 | 使用 Postman 进行接口测试_第18张图片

你可能感兴趣的:(#,python,python,flask)