☰
Python+MySQL管理系统代码包实战:从建库到跑通完整指南
2026/10/14 6:16:38 网站建设 项目流程

简介:基于Flask与MySQL的Python管理系统代码包,实际内容为一个功能完整的个人博客系统,面向正在学习Python Web开发、需要课程设计或快速搭建博客网站的初中级开发者。资源共71个文件,包含10个Python源码文件(涉及app核心包、扩展、模型、工具等)、21个HTML页面、7个CSS样式表与必要的JavaScript脚本,另附SQL数据库脚本和项目日志,可支撑从后端处理到前端渲染的完整流程。压缩包仅807KB,轻量便携;目录中app、models.py、manage.py、blog_db.sql等模块划分清楚,便于按块阅读和二次扩展。目前已有629人学习下载,适合用来理解Flask+MySQL的典型分层结构、用户登录与文章管理逻辑,涵盖文章增删改查、分类展示及后台管理入口等典型场景,也可作为毕业设计或作品集项目的基础框架。

1. 拿到这份 Python+MySQL 管理系统代码.zip,先别急着双击 app.py

每学期课程设计季,总会有人在群里发来一份「Python管理系统(python+mysql)代码.zip」,说解压之后怎么都跑不起来。这个 zip 其实是管理系统开发的一个最小闭环样本:Python 负责业务逻辑,MySQL 负责数据落库,页面负责交互,代码量不大,但已经把登录、增删改查、数据库读写这些骨架全搭好了。它的价值不在于代码写得有多花哨,而在于让你照着这条链路学会「先建库、再连库、最后写接口」的正确顺序。这篇文章会把这套系统的结构、启动步骤、核心代码和常见报错逐一拆开,新手照着能跑通,熟手也能直接拿这套思路去改自己的课设或毕设。

2. 先别急着跑:这类代码包里最值得抄的三层结构

解压 zip 之后,我一般不会第一时间去找 app.py 双击,而是先看三样东西:目录结构、数据库访问方式、建表脚本。这三样决定了一个管理系统能不能在两小时内跑起来,也决定了你后面改业务时会不会越改越乱。

2.1 目录结构先判断框架:Flask、Django 还是手写 socket

打开 zip 先扫一眼根目录,一般能直接判断出它用的是哪一套方案。最常见的是 Flask 风格:根目录下放着 app.py 或 run.py,旁边有 models.py、db.py,再往下是 templates/ 和 static/ 两个文件夹,外加 requirements.txt 和一份 db.sql。这种结构里 app.py 是入口,templates 放模板页面,static 放 CSS 和 JavaScript,数据库初始化脚本通常叫 init.sql 或者直接写在 README 里。判断框架的目的不是为了炫技,而是为了知道报错往哪里看:Flask 的报错会直接指向 app.py 里的视图函数,模板找不到会提示 templates 路径不对;如果看到 manage.py 和 settings.py,那就是 Django 项目,数据库配置在 settings.py 里,启动命令也变成了 python manage.py runserver;要是整个 zip 只有一个 .py 文件,连 Flask 都没引入,那多半是手写 socket 的老式作业,这种不建议继续深改,当作思路参考就好。还有一种更隐蔽的情况:zip 里带了两个入口文件,一个旧的 app.py 和一个新加的 run.py,这种我一般以 run.py 为准,因为它通常是作者最后改完能跑的那一版。

2.2 数据库访问层二选一:PyMySQL 直连还是 SQLAlchemy ORM

管理系统代码包里最常见的数据库访问方案就两种:PyMySQL 直连 SQL,或者 SQLAlchemy 做 ORM。PyMySQL 直连的管理系统,代码里能看到pymysql.connect()和cursor.execute("SELECT ..."),SQL 写得明明白白,排错时直接拿这条 SQL 放到 MySQL 命令行里执行,结果一目了然。ORM 方案则会在代码里看到db.session.query(User)这类写法,模型关系清楚,但出问题时报错会包好几层,不熟的人容易被绕晕。我一般建议:如果 zip 用的是 PyMySQL,就别强行改成 ORM;如果 zip 用的是 ORM,也别硬翻译回 SQL。先按原方案跑通,再谈重构,否则你会在「环境还没起来」的阶段同时踩两套技术栈的坑。下面这张表可以帮你快速判断自己手里这套值不值得继续投入:

对比项PyMySQL 直连SQLAlchemy ORM
上手门槛低,SQL 写出来就能跑高,要理解模型和会话
调试直观度报错直接指向 SQL报错多包一层,需要剥开
改表成本改表和 SQL 同步改改模型后还要处理迁移
适合场景课设、小型管理系统表多、关系复杂的毕设

补充一句,管理系统最核心的价值是「把业务数据管起来」,这离不开增删改查和统计查询,而这些恰恰是 SQL 最容易表达的。只要代码包里的 SQL 写得有纪律,比如统一用参数占位符、不拼接字符串,这套代码就值得留下来继续改。

2.3 三张表就能撑起一个管理系统:user、role 与业务表设计

不管这个管理系统是管图书、员工还是设备,底层都逃不过三张核心表:用户表、角色表、业务表。用户表存登录账号和密码哈希,角色表存管理员和普通用户的区分,业务表才是这个系统真正要管理的对象。很多课程设计系统把角色字段直接写在 user 表里,比如加一个role VARCHAR(20),这样做在小项目里可以省一张表,但权限判断会越来越别扭。我更习惯把角色拆成独立表,用户表通过外键引用角色 ID,这样后面加权限、做拦截都顺。建表脚本通常长这样:

CREATE TABLE role ( id INT AUTO_INCREMENT PRIMARY KEY, role_name VARCHAR(32) NOT NULL UNIQUE ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4; CREATE TABLE user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(64) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, real_name VARCHAR(64) DEFAULT '', role_id INT NOT NULL, created_at DATETIME DEFAULT CURRENT_TIMESTAMP, KEY idx_role (role_id), CONSTRAINT fk_user_role FOREIGN KEY (role_id) REFERENCES role(id) ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

角色表先插入两条数据,比如管理员和普通用户,用户表里的账号再指向对应角色 ID。业务表就看具体项目了,图书管理系统加 book 表,员工管理系统加 employee 表,套路都是:主键 ID、业务编号、名称、状态、创建时间和若干业务字段。如果 zip 里没有建表脚本,就按这三张表的思路自己补一份,管理系统的主体结构立刻就有了。这里有个关键点:所有表都要用 InnoDB 引擎,因为外键约束和事务回滚都依赖它,用 MyISAM 的表在删除和修改时容易留下半截数据。

提示:拿到代码包后先找建表脚本,找不到就按 user、role、业务表的结构自己建,不要直接拿着代码里的 SQL 现场猜表结构。

3. 把 zip 跑成本地可运行系统:环境、建库与最小启动命令

这一章解决「怎么跑起来」的问题。我的习惯是严格按顺序做三步:先建 Python 虚拟环境,再初始化 MySQL 数据库,最后改配置启动项目。顺序反了会出现各种莫名其妙的报错,比如代码里连的数据库还不存在,Flask 启动倒是没问题,访问页面却全在报 500。环境准备是这套流程里最不性感却最容易翻车的一步。

3.1 用虚拟环境隔离依赖:requirements.txt 缺失时手动装

不管 zip 里有没有 requirements.txt,我都建议先建一个干净的虚拟环境,避免把你本机的 Python 环境搞乱。项目目录下执行:

cd 解压出来的项目目录 python3 -m venv venv source venv/bin/activate # Windows 下用 venv\Scripts\activate pip install -r requirements.txt

如果解压后发现没有 requirements.txt,也别慌,管理系统项目依赖其实非常收敛,最常见的就是 Flask、PyMySQL 和 cryptography。手动装也行:

pip install flask pymysql cryptography

这里的cryptography不是可选项。MySQL 8 及以上版本的默认认证插件是 caching_sha2_password,PyMySQL 在连接时需要通过 cryptography 做 RSA 公钥加密传输,缺了它会在连接阶段直接报错,提示你安装 cryptography。装完依赖后,可以用pip freeze | grep -i -E "flask|pymysql|cryptography"看一眼实际装上的版本,如果和你系统里的其他包冲突,就把pip install改成在虚拟环境内部执行,不要动全局 Python。

3.2 MySQL 建库与导入:字符集、账号授权和 source 命令

数据库这一步是管理系统能不能跑的胜负手。首先确认 MySQL 服务已经启动,然后在命令行里用 root 登录,执行建库、建账号、授权三步:

CREATE DATABASE manage_sys DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER 'manage_user'@'localhost' IDENTIFIED BY '你的密码'; GRANT ALL PRIVILEGES ON manage_sys.* TO 'manage_user'@'localhost'; FLUSH PRIVILEGES;

DEFAULT CHARACTER SET utf8mb4这段比很多人想象的重要。如果省略掉,MySQL 会用默认的字符集建库,老版本默认可能是 latin1,后面中文数据全部变成问号,再回头改就是一遍遍折腾表结构。CREATE USER指定了登录账号和密码,GRANT ... ON manage_sys.*的意思是只给这个账号操作 manage_sys 库里所有表的权限,不涉及其他库。本地练习可以直接 GRANT ALL,但要清楚这条权限比较大,正式环境里一般只给 SELECT、INSERT、UPDATE、DELETE。建好库之后导入初始化脚本:

mysql -u manage_user -p manage_sys < db.sql

如果 zip 里的建表脚本叫 init.sql 或者 database.sql,把文件名换掉就行。导入时如果报ERROR 1366或者中文乱码,先检查 SQL 文件本身是不是 UTF-8 编码,Windows 记事本另存时选 UTF-8,不要选 ANSI。导入完成后再执行SHOW TABLES;确认表已经建好,这一步能帮你避开几乎所有「代码跑起来但页面全白」的问题。

3.3 集中改配置再启动:config.py 里千万别写死密码

管理系统代码包的配置一般集中在 config.py 或者 app.py 顶部。我习惯把所有数据库连接信息收敛到 config.py 里,业务代码只负责读取配置,不要到处写连接字符串。一个典型的配置长这样:

import os class Config: SECRET_KEY = os.getenv("SECRET_KEY", "dev-only-change-me") DB_HOST = os.getenv("DB_HOST", "127.0.0.1") DB_PORT = int(os.getenv("DB_PORT", 3306)) DB_USER = os.getenv("DB_USER", "manage_user") DB_PASSWORD = os.getenv("DB_PASSWORD", "你的密码") DB_NAME = os.getenv("DB_NAME", "manage_sys") DB_CHARSET = "utf8mb4"

SECRET_KEY 是给 session 签名用的,Flask 的 session 内容存在 Cookie 里,没有这个密钥就无法安全签名,管理系统登录后跳转都会受影响。DB_PORT 之所以要包一层int(),是因为环境变量读出来是字符串,pymysql.connect 的 port 参数必须传整数。所有配置都留了os.getenv的默认值,意思是你哪怕不改环境变量,只要把密码这项改掉就能本地跑起来。启动项目:

source venv/bin/activate python app.py

浏览器打开http://127.0.0.1:5000。如果页面能开但登录时报数据库连接错误,回到 3.2 检查库名和账号;如果命令行直接提示ModuleNotFoundError: No module named 'pymysql',回到 3.1 确认依赖装进了当前虚拟环境,而不是装到了全局 Python。

注意:启动日志显示Running on http://127.0.0.1:5000只代表 Flask 起来了,不代表数据库通了,真正验证连库是否成功,要看登录页提交后的行为。

4. 核心模块的 Python 代码长什么样:登录、会话与 CRUD 拆解

跑通之后就可以开始读代码了。管理系统代码包里的核心逻辑并不复杂,翻来覆去就是三块:用户登录与会话、业务数据的增删改查、数据库连接的获取与释放。把这三块看明白,一套系统基本就掌握了一半。下面我会按「最常见的管理系统写法」把三段代码展开,代码并不来自某个特定项目,而是这类系统里出现频率最高的标准形态。

4.1 登录与会话:密码哈希校验和 session 注入

登录接口是所有管理系统默认打不开的门。常见的正统写法是用 Werkzeug 的check_password_hash校验密码,而不是把数据库里的密码字段取出来直接和用户输入做字符串比较。先看代码:

from flask import Flask, request, session, redirect, flash from werkzeug.security import check_password_hash import pymysql app = Flask(__name__) app.config.from_object("config.Config") def get_db(): return pymysql.connect( host=app.config["DB_HOST"], port=app.config["DB_PORT"], user=app.config["DB_USER"], password=app.config["DB_PASSWORD"], database=app.config["DB_NAME"], charset=app.config["DB_CHARSET"], cursorclass=pymysql.cursors.DictCursor, ) @app.route("/login", methods=["POST"]) def login(): username = request.form.get("username", "").strip() password = request.form.get("password", "") conn = get_db() try: with conn.cursor() as cursor: cursor.execute( "SELECT id, username, password_hash, role_id FROM user " "WHERE username=%s LIMIT 1", (username,), ) row = cursor.fetchone() finally: conn.close() if row and check_password_hash(row["password_hash"], password): session["uid"] = row["id"] session["role_id"] = row["role_id"] return redirect("/index") flash("用户名或密码错误") return redirect("/login")

这段代码里有三个地方值得细看。第一,SQL 里用的是%s占位符,参数通过 execute 的第二个参数传入,而不是用 f-string 拼 SQL,这是防止 SQL 注入最基本的写法。第二,cursorclass=pymysql.cursors.DictCursor让查询结果以字典形式返回,后面row["password_hash"]才能按列名取值,否则拿到的是一堆元组,取字段要数位置,很容易错。第三,LIMIT 1限制了查询只返回一行,因为 username 在建表时有 UNIQUE 约束,理论上有且仅有一行,但加上 LIMIT 能让数据库省掉多余的扫描,也让代码意图更明确。

登录成功之后,session["uid"]和session["role_id"]被写入了会话。后续所有需要登录才能访问的页面,只需要在视图函数开头检查这两个 session 变量是否存在,不存在就直接重定向到 /login。这里要注意:session 的密钥来自 config.py 里的 SECRET_KEY,如果没配置或者随便写了个空的,登录状态会在服务重启后失效,用户明明刚登录过,刷新一次又要重新登录。

4.2 用户列表与删除:参数化查询、分页与事务

管理系统里出现频率最高的接口就是列表和删除。列表要支持关键字搜索和分页,删除要支持整行移除且不能留下脏数据。我一般会把列表查询写成这样:

@app.route("/user/list") def user_list(): keyword = request.args.get("keyword", "").strip() page = max(int(request.args.get("page", 1)), 1) page_size = 10 offset = (page - 1) * page_size conn = get_db() try: with conn.cursor() as cursor: if keyword: cursor.execute( "SELECT id, username, real_name, role_id FROM user " "WHERE username LIKE %s OR real_name LIKE %s " "ORDER BY id DESC LIMIT %s OFFSET %s", (f"%{keyword}%", f"%{keyword}%", page_size, offset), ) rows = cursor.fetchall() else: cursor.execute( "SELECT id, username, real_name, role_id FROM user " "ORDER BY id DESC LIMIT %s OFFSET %s", (page_size, offset), ) rows = cursor.fetchall() with conn.cursor() as cursor: if keyword: cursor.execute( "SELECT COUNT(*) AS total FROM user " "WHERE username LIKE %s OR real_name LIKE %s", (f"%{keyword}%", f"%{keyword}%"), ) else: cursor.execute("SELECT COUNT(*) AS total FROM user") total = cursor.fetchone()["total"] finally: conn.close() return render_template("user_list.html", rows=rows, total=total, page=page, page_size=page_size)

这里有两个容易漏掉的细节。分页的LIMIT %s OFFSET %s两个参数都是整数,PyMySQL 在传参时能正确处理,不需要手工拼进 SQL。LIKE搜索里的%是关键字模糊匹配的通配符,f"%{keyword}%"表示包含关键字即可,但要注意如果关键字本身包含%或_,需要额外处理转义,否则搜索行为会超出预期。COUNT(*)和列表查询分开执行,是为了在数据量大时更清楚地区分「查询结果」和「总条数」两类职责,模板里算总页数时用(total + page_size - 1) // page_size。

删除接口则要处理事务和请求方式两件事:

@app.route("/user/delete/<int:uid>", methods=["POST"]) def user_delete(uid): conn = get_db() try: with conn.cursor() as cursor: cursor.execute("DELETE FROM user WHERE id=%s", (uid,)) conn.commit() except Exception: conn.rollback() raise finally: conn.close() return redirect("/user/list")

删除操作必须用 POST 而不是 GET,因为 GET 请求会被浏览器预加载、被外部链接直接触发,一个<img src=".../user/delete/1">就能删掉一条数据,这在管理系统里是不可接受的。conn.commit()提交事务,conn.rollback()在异常时回滚,保证删除要么成功要么对数据库毫无影响。这里还有个常见的业务陷阱:如果 user 表被其他业务表通过外键引用,直接 DELETE 会触发外键约束报错。遇到这种情况,常见做法是改成逻辑删除,给 user 表加一个status字段,删除时把 status 改成 0,列表查询默认过滤 status=1,这样既保住了数据关联,也保住了演示时「删除成功」的效果。

4.3 连接管理:用请求级上下文避免连接泄漏

前面的代码每次都调用get_db()新建连接、用完再 close,这是最直白的写法,但页面多了之后会有两个问题:一是每个函数都要写finally: conn.close(),漏掉一次就连接泄漏;二是高一点访问量下频繁新建和销毁连接,MySQL 的并发连接数很容易被打满。更稳的做法是把数据库连接挂到 Flask 的请求上下文上,同一个请求内复用同一个连接,请求结束自动关闭:

from flask import g def get_db(): if "db" not in g: g.db = pymysql.connect( host=app.config["DB_HOST"], port=app.config["DB_PORT"], user=app.config["DB_USER"], password=app.config["DB_PASSWORD"], database=app.config["DB_NAME"], charset=app.config["DB_CHARSET"], cursorclass=pymysql.cursors.DictCursor, ) return g.db @app.teardown_appcontext def close_db(exc=None): db = g.pop("db", None) if db is not None: db.close()

g是 Flask 提供的请求级全局变量,同一个请求里不管调用多少次get_db(),拿到的都是同一个连接,请求结束后 Flask 会回调teardown_appcontext,把保存在g.db里的连接取出来关闭。g.pop("db", None)取连接的同时把键删掉,防止连接被重复关闭。这套写法改造成本很低,前面的user_list和login函数都不用改,因为它们调用的还是get_db(),只是内部实现变得更安全了。注意改造后不要再手动conn.close(),否则请求还没结束连接就被关掉,后面再查询时会报MySQL server has gone away。

5. 常见问题与避坑:为什么连不上、乱码、登录失败、页面 500

这一章写的都是我在带人跑代码时反复遇到的真实问题,按「现象 → 原因 → 解决」的顺序给出来。凡是跑系统翻车,九成以上都能归到这四类里面。

5.1 连不上数据库:先确认服务在跑,再查授权和端口

现象是启动 Flask 不报错,但一提交登录表单就提示pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1:3306' (10061)")。很多同学第一反应是去改代码里的密码,其实这个错误码根本没有走到密码校验那一步,TCP 层都没连上。原因基本是三种:MySQL 服务没启动、端口不是 3306、账号只允许从别的地址登录。先看服务和端口:

# Linux / macOS systemctl status mysql 2>/dev/null || service mysql status ss -tlnp | grep 3306

Windows 下打开服务管理器找 MySQL 开头的服务,确认状态是正在运行。如果服务在跑但端口不是 3306,说明 MySQL 改过端口,去 config.py 把 DB_PORT 改成实际端口。如果端口正常,就检查账号授权,用 root 登录后执行:

SELECT user, host FROM mysql.user;

如果 manage_user 的 host 是localhost,而代码里 DB_HOST 写的是127.0.0.1,在某些 MySQL 版本里会被当成两个不同的地址。要么把两个统一,要么执行ALTER USER 'manage_user'@'localhost' IDENTIFIED BY '你的密码';重设密码后再试。超过两分钟还连不上,就先把防火墙临时关掉排除干扰,本地环境一般是防火墙拦了 3306 端口。

5.2 中文全部变成问号:字符集三处要统一

现象是 MySQL 命令行里能正常显示中文,但页面写入的中文到库里全变成???,或者库里数据正常、页面读出来是乱码。原因在于字符串从客户端到数据库要经过连接层和存储层两道关口,任何一层字符集不匹配都会出问题。最容易被忽视的是 PyMySQL 连接时没传 charset 参数:

pymysql.connect(..., charset="utf8mb4")

光在 config.py 里写DB_CHARSET没用,connect()必须真的把这个参数传进去。另一个常见的坑是建库时用了DEFAULT CHARACTER SET utf8mb4,但个别表在建表时被老脚本指定成了 latin1,这时候用SHOW CREATE TABLE user;查看表定义,如果看到CHARSET=latin1,执行:

ALTER TABLE user CONVERT TO CHARACTER SET utf8mb4;

注意这里的重建转换会重写整张表,数据量大时会有锁表时间,本地课设无所谓,生产环境要在低峰期做。最后,如果是在 Windows 命令行里手工往表里插中文,还要在插入之前执行SET NAMES utf8mb4;,否则命令行客户端传出去的字节就不是 UTF-8。三处统一:建库字符集、表字符集、连接字符集,缺一不可。

5.3 用户名密码都对但登录失败:哈希算法不一致

现象是数据库里能看到账号和密码,登录却一直提示用户名或密码错误,复制粘贴密码也没用。原因往往是这套代码的「注册写入密码」和「登录校验密码」用了两套机制。比如把代码跑给管理员演示时,管理员直接在 MySQL 命令行里执行了INSERT INTO user ... VALUES ('admin', '123456'),明文密码进了 password_hash 字段,而登录代码用的是check_password_hash去校验,Werkzeug 的哈希格式是pbkdf2:sha256:...,拿明文123456去比当然失败。反过来也有:某些老代码直接WHERE password = '123456',但库里存的是哈希串,同样对不上。

解决方法是统一密码体系。以 Werkzeug 为准,对已有明文账号做一次性迁移:

from werkzeug.security import generate_password_hash # 伪代码:连接数据库,逐行读取用户表 # 每次取出一行里的 id 和明文密码 password # 执行 UPDATE user SET password_hash=%s WHERE id=%s # 参数依次是 generate_password_hash(password), id

务必记住,密码哈希是不可逆的,网上说的「解密哈希」基本都是撞库,不要在这上面浪费时间。如果库里既有明文又有哈希,没法靠一条 UPDATE 全量搞定,那就把明文部分按上面的脚本重写成哈希,或者直接重置密码,管理员账号统一改成一个临时密码再让用户自己改。迁移完成后再登录,原理和现象就对齐了。

5.4 页面能开、一提交就 500:按 traceback 退到底层

现象是最典型的:列表页、首页都能正常打开,一点「新增」「删除」「保存」按钮就白屏,地址栏还是原来的 URL,响应码 500 Internal Server Error。原因很多,字段名打错、模板里遍历了 None、删除时有外键约束、表单提交的字段和后端接收的名字不一致,都会导致 500。这类问题最大的困难不是修,而是找到真正的报错在哪。本地调试时,先把 Flask 的 debug 开关打开:

if __name__ == "__main__": app.run(debug=True, host="127.0.0.1", port=5000)

刷新页面再点一次提交,浏览器和命令行都会输出完整 traceback。排错顺序有讲究:不要从第一行开始看,直接从最底部的报错行往上翻。最下面一行是 Python 执行时真正出错的代码位置,上面几行是调用链。看到KeyError: 'xxx'就是模板或代码里访问了一个不存在的字典键;看到TypeError: 'NoneType' object is not iterable就是查询结果为空但代码直接 for 循环了;看到IntegrityError就是外键或唯一约束冲突。如果项目部署环境不方便开 debug,就在视图函数入口临时包一层 try/except,手动打印异常到服务器日志:

import traceback try: # 原视图逻辑 pass except Exception: traceback.print_exc() return "error", 500

这个临时壳子只用来定位问题,定位完就删掉,不要留着进交付代码。debug=True 也是同理,本机调试能用,交付前必须关掉,否则别人拿到项目一启动就能看到你的源码路径和配置信息。

6. 交差之前:用一条完整链路验收你的管理系统

跑通 demo 只是第一步,真正的验收标准是「从登录到退出」这条链路全程不卡壳。以前我见过太多现场翻车的情况:管理员能登录,但新增一条数据之后列表没刷新;普通用户能登录,但还能直接访问管理员的删除接口;退出登录之后按浏览器后退键,又能回到后台页面。这些问题不是 bug 有多大,而是从来没有按链路整体走一遍。我习惯在交付前用下面这张表过一遍:

检查项怎么验证通过标准
登录输错密码三次,再用正确密码登录错误有提示,正确能进首页
权限用普通账号访问管理员删除接口被拦截或提示无权限
增删改新增、编辑、删除各走一遍列表实时变化,无 500
退出退出后按浏览器后退键跳回登录页,不能看到后台数据
数据落库在 MySQL 命令行查最新数据和页面显示一致

如果哪一项没通过,按第 5 章的思路去查,基本都能在半小时内定位。做得再精细一点,给系统补一个最简单的备份脚本,答辩被问到「数据安全」时非常加分:

mysqldump -u manage_user -p manage_sys > backup_$(date +%Y%m%d).sql mysql -u manage_user -p manage_sys < backup_$(date +%Y%m%d).sql

备份输出一个 SQL 文件,恢复时重新导入同名库即可。这个脚本本身不值钱,但它代表你理解「数据是系统的资产」这个点。我最早拿到这种管理系统包时,第一反应也是双击 app.py,后来被连不上库、中文乱码、对不上密码这几个问题轮番教育之后,养成的习惯是:先看建库脚本,再改数据库配置,最后才启动项目,这套顺序帮我挡掉了大半的翻车。照着这个顺序走,你也能少走几步弯路,希望帮到你。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询