☰
Flask+LayUI+MySQL:快速搭建后台管理系统网站模板
2026/9/26 20:09:56 网站建设 项目流程

简介:面向Python Web开发者的一份实用网站模板,基于Flask、LayUI与MySQL构建,适合需要快速搭建后台管理系统或学习前后端整合的初学者与项目开发者。压缩包共233个文件,涵盖58个Python源码、32个HTML页面、36个JavaScript脚本、9个CSS样式,以及GIF演示动图、图标字体、配置文件等辅助内容,整体仅1.29MB,结构轻量且便于按功能模块查阅。目前已有1583人浏览学习,可用作个人项目的起步脚手架。模板中内置了前后端交互示例、页面布局与样式、数据库相关代码,并配有动图说明运行效果,能帮助读者理解Flask路由、模板渲染与LayUI组件的实际结合方式,减少从零搭建环境的成本。

1. Flask 写后端、LayUI 做界面、MySQL 存数据:这套模板帮你跳过最枯燥的那层壳

挺多人学 Flask 学到路由、请求都会了,卡在最尴尬的一步:接口写完了,界面怎么又快又像样?用原生 HTML 拼页面,写十个表单能把手写酸;直接上 Vue,又得补一整套前端工程化。这套 python + flask + LayUI + mysql 网站模板,把三件事打包在一起:Flask 负责路由和接口,LayUI 负责表格、弹窗、表单这些现成组件,MySQL 负责数据落库。模板里带好初始化 SQL、配置文件和能直接跑起来的前后端骨架,你改掉数据库密码、跑一遍建表脚本,就能在本地把页面点开。适合两种人:刚学完 Flask 基础、想快速拿出完整项目的新手,以及要在两周内交付内部系统的小团队。

2. 动手前先看懂模板:目录、建表脚本和配置项

先把基础环境过一遍。如果你还在照着 python 安装教程装解释器,记得把 Add Python to PATH 勾上,不然后面 pip 装依赖会报“不是内部或外部命令”。MySQL 没装的话去官网下载安装包,装完 root 密码记牢,一会儿 config.py 里要填。下面几步按顺序走,可以避掉大多数“模板跑不起来”的求助帖。

2.1 目录结构拆解:哪个文件是入口,哪个目录放页面

解压后别急着双击 app.py。先把目录结构过一遍,知道哪里是入口、哪里有配置、哪里放页面。一个标准的 Flask + LayUI + MySQL 模板,目录通常是这样的:

website_template/ ├── app.py # Flask 入口,注册路由和蓝图 ├── config.py # 数据库连接、密钥、端口配置 ├── requirements.txt # 依赖清单,pip 安装用 ├── db/ │ └── init.sql # 建库建表脚本 ├── static/ │ └── layui/ # LayUI 的 css、js、字体文件 ├── templates/ │ ├── base.html # 公共父模板,导航和底部都在这里 │ ├── index.html # 首页 │ ├── user_list.html # 用户列表示例页 │ └── user_form.html # 用户新增/编辑弹窗页 └── utils/ ├── db.py # pymysql 连接封装 └── response.py # 统一 JSON 返回格式

app.py 只做路由注册和 Flask 实例初始化,业务 SQL 不放这里。config.py 把所有环境相关的东西隔离出来,后面部署到服务器只需要改这一个文件。static 目录放 LayUI 的静态资源,templates 放 Jinja2 模板,utils 下面放数据库连接和响应封装。这个拆法的好处是,你后面每加一个模块,路径都是固定的:templates 多一个页面,app.py 多一组路由,数据库多两张表,互不干扰。

templates 和 static 是 Flask 的约定目录。如果你为了好看改了这两个文件夹名,Flask 不会自动识别,必须创建 Flask 实例时手动指定 template_folder 和 static_folder。模板里用的就是默认约定,所以第一次跑之前,尽量保持路径别动,先跑通再谈重排目录。

2.2 MySQL 建表脚本:建库语句定死字符集和引擎

数据库脚本是整个模板的地基。初始化 SQL 里通常会有建库语句和几张示例表,核心代码一般长这样:

CREATE DATABASE IF NOT EXISTS website_demo DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci; USE website_demo; CREATE TABLE IF NOT EXISTS user ( id INT AUTO_INCREMENT PRIMARY KEY, username VARCHAR(50) NOT NULL UNIQUE, password_hash VARCHAR(255) NOT NULL, role TINYINT DEFAULT 1 COMMENT '1 普通用户,2 管理员', status TINYINT DEFAULT 0 COMMENT '0 正常,1 禁用', created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP, updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP ) ENGINE=InnoDB;

第一处要盯着的是 DEFAULT CHARACTER SET utf8mb4,不是 utf8。utf8mb4 才是真正的完整 UTF-8,能存 Emoji 和生僻字;utf8 在 MySQL 里是 utf8mb3 的别名,遇到四字节字符会报错或存成问号。第二处是 ENGINE=InnoDB,别用 MyISAM。如果模板涉及事务和多表关联,MyISAM 不支持事务回滚和行级锁,删一条数据崩一片的场面就这么来的。

字段默认值也值得保留。status TINYINT DEFAULT 0 比允许 NULL 好,统计时直接 COUNT 就行,不用处理 NULL 转 0。created_at 和 updated_at 建议保留默认写法,自动记录创建和更新时间,插入的时候少写两个字段。如果你在表结构里看到某张业务表没有这两列,最好自己补上,几乎所有列表页都要按时间倒序。

执行建表脚本,命令行方式:

mysql -u root -p < db/init.sql

输入密码时屏幕不显示字符,这不是卡死。执行完用 mysql -u root -p -e "USE website_demo; SHOW TABLES;" 确认表建出来了。如果提示权限不足,回到 MySQL 给当前用户授权,注意别顺手把所有库都放开。开发环境随意,生产环境放开就等着被扫描器问候了。

2.3 配置文件没改对,整个项目起不来

模板里最能决定成败的是 config.py。把数据库连接参数改成你本机实际环境,我一般这样写:

import os class Config: SECRET_KEY = os.environ.get('SECRET_KEY', 'dev-secret-key-change-me') DB_HOST = os.environ.get('DB_HOST', '127.0.0.1') DB_PORT = int(os.environ.get('DB_PORT', 3306)) DB_USER = os.environ.get('DB_USER', 'root') DB_PASSWORD = os.environ.get('DB_PASSWORD', '123456') DB_NAME = os.environ.get('DB_NAME', 'website_demo') DB_CHARSET = 'utf8mb4'
参数含义常见坑
DB_HOSTMySQL 地址写 localhost 和 127.0.0.1 在 Linux 上行为不同
DB_PORTMySQL 端口不是 3306 时改这里,别去改 MySQL 配置
DB_USER / DB_PASSWORD登录账号密码密码含特殊字符时注意转义
DB_NAME数据库名必须和 init.sql 里的库名一致
DB_CHARSET连接字符集和建库字符集不一致会出现乱码

代码里用 os.environ.get 提供默认值,是给不同环境留口子。本地开发不用设环境变量,直接改默认值就能跑;部署到 Linux 服务器时用环境变量覆盖,避免把数据库密码提交到 Git 仓库。DB_HOST 的坑在第 5 章展开,先记着:Windows 上 localhost 和 127.0.0.1 差别不大,Linux 上 localhost 会让 pymysql 走 Unix socket,很多 MySQL 默认不开启那个 socket,连不上就报 error 2002。

config.py 改完,安装依赖。模板里通常有 requirements.txt,按下面顺序来:

cd website_template python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install -r requirements.txt python app.py

用虚拟环境不是为了好看,是为了防止服务器上全局 Python 环境里旧版本 Flask 把项目带进尴尬的中间态。pip install 完成后看到 Flask、pymysql 都装上了再启动。如果 python app.py 后提示端口被占用,先不要怀疑模板有 bug,看一下是不是 5000 端口被别的服务占了。

3. Flask 路由与 LayUI 页面渲染:从模板继承到接口数据

这一章解决“Flask 如何绑定到网页元素”的疑问。LayUI 是纯前端框架,Flask 是纯后端,二者的连接点是 HTML 模板和 AJAX 接口。写清这一点,后面的数据展示、表单提交才有着落。

3.1 Jinja2 模板继承:把 LayUI 的公共壳抽成一个 base.html

LayUI 的侧边导航、顶部栏、JS 引入代码在每个页面几乎一样。直接在每页复制粘贴,后面改一个菜单名要翻十几个文件。模板里应该用 Jinja2 的继承机制,把公共部分收敛到 base.html:

<!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>{% block title %}默认标题{% endblock %}</title> <link rel="stylesheet" href="{{ url_for('static', filename='layui/css/layui.css') }}"> {% block head %}{% endblock %} </head> <body> <div class="layui-layout layui-layout-admin"> <div class="layui-header">顶部导航</div> <div class="layui-side"> <ul class="layui-nav layui-nav-tree"> <li class="layui-nav-item"><a href="/user/list">用户管理</a></li> <li class="layui-nav-item"><a href="/process/list">流程审批</a></li> </ul> </div> <div class="layui-body"> {% block content %}{% endblock %} </div> </div> <script src="{{ url_for('static', filename='layui/layui.js') }}"></script> {% block script %}{% endblock %} </body> </html>

关键在 url_for。它根据 Flask 的静态目录配置反向拼出资源完整 URL,比手写 /static/layui/css/layui.css 更可靠。以后给静态文件加版本号、换 url 前缀,手写路径会全部失效,url_for 能自动跟随变化。block 是子模板用来覆盖的锚点,子页面只需要填自己的内容。

子页面继承方式:

{% extends "base.html" %} {% block content %} <div class="layui-card"> <div class="layui-card-header">用户列表</div> <div class="layui-card-body"> <!-- 这里写自己的内容 --> </div> </div> {% endblock %}

子模板只写 content 部分,头部、导航、脚本引用全部从父模板继承。这个结构是模板里最值得保留的设计,后面加页面都按这个套路走。如果后面要做权限控制,不同角色看不同菜单,也是改 base.html 里的菜单块,不需要改每个页面。

3.2 视图函数与页面数据:render_template 传了哪些变量

页面要显示数据库里的数据,需要一个视图函数准备好数据。模板里典型的列表页路由:

@app.route('/user/list') def user_list_page(): users = query_all_users() return render_template('user_list.html', users=users, page_title='用户管理')

query_all_users() 在第 4 章实现。这里先理解数据流:render_template 的第二个参数开始,是模板里能直接使用的变量。user_list.html 里用 Jinja2 循环渲染:

<table class="layui-table"> <thead> <tr><th>ID</th><th>用户名</th><th>创建时间</th></tr> </thead> <tbody> {% for user in users %} <tr> <td>{{ user.id }}</td> <td>{{ user.username }}</td> <td>{{ user.created_at }}</td> </tr> {% endfor %} </tbody> </table>

这种写法适合数据量小、不需要分页筛选的页面。特点是服务端渲染,整页刷新。如果要加搜索筛选,再往下走就得上 3.3 的远程表格。

有一个坑必须提醒:模板里写 user.username,要求查询返回的每一行是字典或对象。pymysql 的默认返回结果是元组,必须用 DictCursor 才能通过 user['username'] 取字段。如果用户列表页一跑就报 jinja2.exceptions.UndefinedError,八成是这个没配。返回字段顺序和 SELECT 顺序一旦变化,元组方式还可能把用户名和密码位置搞混,那时不是报错而是数据错乱,更隐蔽。

3.3 LayUI 表格吃接口:统一 JSON 格式,一次配好后端只管返回数据

LayUI 的 table 组件支持远程数据,自己发 AJAX、渲染表格、处理分页。页面里配置:

table.render({ elem: '#userTable', url: '/api/user/list', page: true, cols: [[ { field: 'id', title: 'ID' }, { field: 'username', title: '用户名' }, { field: 'created_at', title: '创建时间' } ]], response: { statusName: 'code', msgName: 'msg', countName: 'count', dataName: 'data' } });

对应的 Flask 接口返回结构要跟 response 配置对齐:

@app.route('/api/user/list') def api_user_list(): page = int(request.args.get('page', 1)) limit = int(request.args.get('limit', 10)) total, rows = query_users_page(page, limit) return jsonify({'code': 0, 'msg': '', 'count': total, 'data': rows})

LayUI 的默认约定是 code=0 表示成功,msg 是错误信息,count 是总数,data 是当前页数据。后端只要返回这个结构,表格自动渲染数据和分页条。字段名对不上就出问题:

LayUI 期望字段含义后端返回不一致时的表现
code=0成功标志表格一直转圈,不渲染数据
msg提示信息失败时不显示原因
count数据总数分页总数显示 0
data当前页数据表格空白,无报错

前端自动带上 page 和 limit 参数:page 是当前页码,limit 是每页条数。后端从 request.args 里读这两个值,再传给 SQL 的 LIMIT 和 OFFSET,这套配合的关键细节放在第 4.2 节。

4. 数据库交互实操:连接封装、分页查询、事务与 SQL 安全

这一章对应“web 页面详细步骤实现代码和 mysql 数据设计表”的诉求。前端页面只是壳,模板真正值钱的是后端和 MySQL 的交互方式,以及那几个最容易写错的数据处理细节。

4.1 pymysql 连接封装:为什么模板常用每次请求新建连接

模板里最标准的连接封装是独立的 utils/db.py:

import pymysql from config import Config def get_conn(): return pymysql.connect( host=Config.DB_HOST, port=Config.DB_PORT, user=Config.DB_USER, password=Config.DB_PASSWORD, database=Config.DB_NAME, charset=Config.DB_CHARSET, connect_timeout=5, cursorclass=pymysql.cursors.DictCursor )

两个参数值得解释。connect_timeout=5 让 MySQL 没响应时 5 秒就报错,不设的话可能等几十秒,页面一直转圈。cursorclass=pymysql.cursors.DictCursor 让查询结果变成字典列表,每行是 {"id": 1, "username": "admin"},Jinja2 里写 user.username 才成立。如果你自己写连接,漏掉 DictCursor,所有模板取值都会报错。

这种写法是每次请求新建连接、用完关闭,不引入连接池。有人觉得浪费,但对中小型内部系统来说代价完全可接受。模板的目标是让你快速跑通,不为并发优化。等线上并发上去了,再替换成 DBUtils 的 PooledDB 或 SQLAlchemy 连接池,接口层不用改,只改 get_conn 内部实现。MySQL 的连接成本在局域网内是毫秒级,真没到需要提前优化的程度。

4.2 分页查询:page、limit 怎么变成 SQL 的 LIMIT 和 OFFSET

配合 LayUI 表格的分页查询,模板里一般是这么写的:

def query_users_page(page, limit): offset = (page - 1) * limit conn = get_conn() try: with conn.cursor() as cur: cur.execute("SELECT COUNT(*) AS total FROM user") total = cur.fetchone()['total'] sql = "SELECT id, username, role, created_at FROM user ORDER BY id DESC LIMIT %s OFFSET %s" cur.execute(sql, (limit, offset)) rows = cur.fetchall() return total, rows finally: conn.close()

容易算错的是 OFFSET:它表示跳过多少条,等于 (page - 1) * limit。第 2 页、每页 10 条,offset 是 10,从第 11 条开始取。很多新手直接写 OFFSET page,结果第二页和第一页数据重叠。还有效率问题:LIMIT 100000, 10 会让 MySQL 先读十万条再丢弃,表大了翻页越来越慢。比较快的做法是记住上一页最后一条 id,用 WHERE id < 上页边界 ORDER BY id DESC LIMIT 10,复杂系统分页优化基本都是这个思路。

代码里的 %s 是参数化查询。不要自己拼 SQL,比如 f"SELECT ... WHERE id = {user_id}"。用户输入一旦带上 SQL 特殊字符,表都可能被删。pymysql 的 execute 传参数会自动转义和类型处理,所有涉及用户输入的 SQL 都该这么写。

4.3 事务写入:两张表要么全成功,要么全回滚

翻车最多的场景:往主表插一条数据、往日志表插一条记录,第一条成功,第二条报错,数据停在“半成”状态。模板里涉及多表写入应该包事务:

def create_user_with_log(username, password_hash): conn = get_conn() try: with conn.cursor() as cur: cur.execute( "INSERT INTO user (username, password_hash) VALUES (%s, %s)", (username, password_hash) ) new_id = cur.lastrowid cur.execute( "INSERT INTO user_log (target_id, action) VALUES (%s, %s)", (new_id, 'create_user') ) conn.commit() return new_id except Exception: conn.rollback() raise finally: conn.close()

事务边界是 conn.commit() 和 conn.rollback()。commit 之前所有操作都是临时的,只有 commit 成功才算落库。中间任何一步异常,rollback 会撤销前面的改动。注意 pymysql 默认不自动提交,所以你不写 conn.commit(),数据看起来进去了,数据库一查却是空的。

注意:except 里 rollback 之后要 raise 继续抛异常,让 Flask 接口层捕获并返回给前端。如果吞掉异常,调用方以为“新增成功”,数据库里什么都没写,这种错最难查。

4.4 模板里最常见的 SQL 坏味道:字符串拼接、裸 SELECT * 和存储过程

拿到模板后,全局搜一下有没有 execute(f"...") 这种写法。有就趁早改成 4.2 的参数化写法,不要嫌麻烦。还有 SELECT * 的问题,表字段少时看不出毛病,等业务加字段,接口返回数据变大、前端字段错位,排查成本就上去了。把查询字段明确列出来,既是给阅读者看接口返回什么,也是给前后端留一份数据契约。

再说一个是非题:存储过程。模板的 SQL 脚本里如果出现存储过程,建议别沿用。业务逻辑写在 Python 层里,用 Git 能追踪变更,存储过程改起来要单独管理脚本,团队一多就乱套。同理,模板里假如出现 UPDATE 语句不带 WHERE 或者 WHERE 1=1,这属于事故隐患。执行 UPDATE 之前,先跑一条等值 SELECT 看影响行数,再决定下手。MySQL 的 UPDATE 语法本身不复杂,复杂的是你不清楚自己要改多少行。

5. 部署避坑与排查:模板跑通只是开始,过完这四道坎才算真能用

下面这几条是拆这类 Flask + LayUI + MySQL 模板时遇到的真实踩坑记录,每条按“现象 → 原因 → 解决”展开。

5.1 静态文件 404:Flask 静态目录、LayUI 资源与附件路径

现象:首页能打开,但页面没有样式。浏览器 F12 网络面板里 layui.css、layui.js 全部 404;用户上传的图片附件也 404,点击图片地址直接跳到错误页。

原因:模板里用 url_for('static', filename='layui/css/layui.css'),但 Flask 实例创建时没指定 static_folder,或者静态文件实际放在了别的目录下。还有一种情况是蓝图里设置了 static_folder,导致 /static 默认路由没注册。附件路径 404 经常是 Windows 上用 \ 写相对路径,部署到 Linux 后目录分隔符对不上,或者上传目录在 Flask 静态目录之外。

解决:先确认 static 文件夹和 app.py 在同一层。不在同一层,就在创建 Flask 实例时显式指定 app = Flask(name, static_folder='../static')。蓝图场景不要在蓝图里配 static_folder,统一在应用级别配置。附件路径用 os.path.join(app.config['UPLOAD_FOLDER'], filename) 拼,并单独加一个映射路由:

@app.route('/uploads/<path:filename>') def uploaded_file(filename): return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

send_from_directory 会做一次目录穿越校验,比直接拼路径安全。改完重启进程,访问一次资源路径确认返回 200。模板自带 LayUI 资源时,这种 404 九成是目录层级搬动导致,别直接改 HTML 里的路径去碰运气。

5.2 MySQL 连接报错:ERROR 2002 无法通过 socket 连上

现象:在 Linux 服务器上跑 app.py,启动时报 pymysql.err.OperationalError: (2002, "Can't connect to local MySQL server through socket '/tmp/mysql.sock'")。

原因:config.py 里 DB_HOST 写的是 localhost,pymysql 在 Linux 上会默认走 Unix socket 文件,不是 TCP 连接。服务器上的 MySQL 没把 socket 文件放在默认位置,或者没开启 socket,就连接不上。

解决:把 DB_HOST 改成 127.0.0.1,强制走 TCP 连 3306 端口,绕开 socket 路径问题。这个改法在 Windows、Linux、macOS 上通用。改完先用命令行验证通道:

mysql -h 127.0.0.1 -P 3306 -u root -p

如果能登上,说明 TCP 通道没问题,Flask 那边也能通。如果报错,再检查 MySQL 的 bind-address 是否绑定了 127.0.0.1,以及用户授权里有没有 'root'@'127.0.0.1' 这个条目。MySQL 用户表里 'root'@'localhost' 和 'root'@'127.0.0.1' 是两条独立授权,只授权 localhost 时 TCP 连接会被拒绝。

5.3 中文乱码:数据库、连接、页面三处字符集对齐

现象:LayUI 页面上显示用户名是问号或“鍚堟硶”这种乱码,数据库里查询也是乱码。还有一种是把 init.sql 里的中文注释变成乱码建进表里。

原因:三层字符集没对齐。第一层是建库时指定字符集,第二层是 pymysql 连接时传的 charset,第三层是 HTML meta 里的 charset。任何一层不一致就乱码。如果是在 Windows cmd 里用 mysql < init.sql 导入,cmd 默认编码是 GBK,脚本里的中文注释也会被当成 GBK 写入,脏数据直接进库。

解决:把三层统一成 utf8mb4。init.sql 建库语句用 utf8mb4,get_conn 里 charset 写 utf8mb4,base.html 的 meta charset 改成 UTF-8。已建好的库执行 ALTER DATABASE website_demo CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci。导入脚本时加上编码参数:

mysql --default-character-set=utf8mb4 -u root -p < db/init.sql

改完重新插一条中文数据,页面和数据库两边都看一眼。连接层和存储层最容易漏,页面层一般默认没问题。

5.4 端口占用、依赖冲突与路径怪癖:本地跑通、线上挂掉的典型原因

现象:本地 python app.py 一切正常,部署到服务器后提示端口被占用,或 ImportError 找不到某个模块,或上传文件后不知道文件存到了哪。

原因:第一种是 5000 端口被服务器其他服务占了。第二种是服务器全局 Python 环境里缺依赖,或有旧版 Flask 冲突。第三种是代码里写死了相对路径“uploads/”,当前工作目录一变,文件就写到别处去了。

解决:端口冲突改 Flask 启动端口,代码里写成可配的:

if __name__ == '__main__': port = int(os.environ.get('PORT', 5001)) app.run(host='0.0.0.0', port=port)

依赖问题在项目目录建虚拟环境,按顺序执行 python -m venv venv、source venv/bin/activate、pip install -r requirements.txt。项目上线时用 pip freeze > requirements.txt 把当前环境版本固下来,别人 clone 下来不会因为依赖版本不同翻车。路径问题用 os.path.join(app.root_path, 'uploads'),root_path 是 Flask 根据生成目录算好的绝对路径,不随启动目录变化。这三类问题在部署阶段几乎必现,提前处理能省一整晚。

6. 改造这门手艺:给模板加一个模块、一层权限、一道搜索

模板的真正价值在于二次开发。这里给一条被验证过的路径,照做不会把项目改坏。

6.1 加一个业务模块的最短路径

拿“用 LayUI 设计流程审批”来说,模板没有审批功能,但你可以按固定路径加上去。第一步在 init.sql 加一张 process 表,字段至少包括 id、title、creator、status、created_at。第二步在 app.py 注册一个蓝图 process_bp,里面写两个路由,一个是页面渲染路由,一个是数据接口路由。第三步在 templates 下新建 process_list.html,继承 base.html,再用 table.render 指到接口。第四步在 base.html 侧边菜单加一个“流程审批”入口。四步做完,一个能分页的审批列表就出来了,后续的步骤条显示、审批按钮都是在这个骨架上加。

6.2 给页面加登录会话:拦截器到底拦什么

内部系统十有八九要登录。模板如果没有 session 控制,加一个 before_request 钩子最快:

@app.before_request def check_login(): allow_list = ['/login', '/static'] if request.path.startswith(tuple(allow_list)): return None if not session.get('user_id'): return redirect(url_for('login_page'))

这个钩子对每个请求都会执行。allow_list 放不校验的路径,比如登录页和静态资源。其他路径如果 session 里没有 user_id,直接重定向到登录页。注意 /static 必须放行,否则 LayUI 的 css、js 会被拦截,登录页直接裸奔。

6.3 搜索与关键词匹配:从 LIKE 到简单相似度

模板自带的列表页多数是查全部,业务上加搜索,最常见的就是 SQL 模糊查询:

SELECT * FROM process WHERE title LIKE %s OR creator LIKE %s

参数是 %关键词%,注意用参数化方式传入,不能拼字符串。如果你在做农产品价格数据可视化这种按名称筛选的系统,这个够用。

如果要做校园失物招领那种关键词相似度匹配,LIKE 只能做全词匹配,做不到“手机”“手机壳”这种相关推荐。低成本方案:把标题和描述拆成关键词列表,用 Python 的集合交集算重合度,重叠超过阈值视为相关。算法不复杂,效果比 LIKE 高一个档次。顺着这个思路,你就能把模板升级成带智能匹配的小平台,比到处找现成系统更靠谱。

最后说一个我自己的习惯。每次拿到这类模板,我不急着改功能,先把 2.3 的配置改好、把 init.sql 跑一遍、用 3.3 的接口测通一个表格,确认前后端链路是通的,才开始动业务代码。这个“先跑通再改造”的顺序让我少踩了很多“改了半天不知道是前端还是后端问题”的坑。从那以后我每次接手 Flask 项目都强制走一遍这个流程,先让骨架活起来,再谈增删改查。这套模板够轻、够直观,按这个顺序走下来,大概率一晚上就能看到自己的第一个页面。希望帮到你。

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

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

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

立即咨询