新手 3 个文件跑通前端 + Flask + MySQL(最小可行 CRUD)

前端页面设计做久了,慢慢地对页面字段与数据库数据之间的关系有了更清晰的认识,于是我开始尝试打通前后端、与数据库之间的连接。

我在实践之后,把"最小可行版本"整理成这篇文章,方便新手朋友们一起学习:用最少的文件,让页面按钮真正把数据写进 MySQL


一、明确一个关键认知:先有数据库表,再有前端页面

前端页面不是凭空设计出来的,它本质上是数据库 Schema 的"可视化操作面板"。

  • 数据库字段(类型、是否可空、主键/外键)决定了前端表单字段、校验规则、下拉选项、列表列名

  • 数据库表之间的关系决定了页面联动与联表展示(比如 employee.branch_id → branch.branch_id)

所以正确顺序通常是:

建库建表(Schema) → DB 层(连接/执行) → API 层(路由/参数解析) → 前端页面(fetch 调用接口)


1. 1 最小可行架构:3 个文件 + 2 个目录

本篇文章用最小结构跑通 查询/新增/修改/删除(CRUD)

注意:HTML 必须放在 templates/,因为 Flask 的模板渲染有"默认规则"。

复制代码
sql连接/
  coffee_app.py         # Flask 入口:路由 /api/...
  coffee_db.py          # DB 层:连接 + query/execute + commit
  templates/
    coffee_admin.html   # 前端页面:按钮 fetch 调接口

1.2 常见问题:

在联调时很容易因为疏忽导致:

前端页面中看似插入了新数据记录,但实际上只是页面里 mock 数据,并没有真实写入数据库。

快速判断方法:

打开浏览器 F12 → Network

  • 如果只看到:GET /api/employees 200

    没看到:POST /api/employees 201
    大概率:保存按钮没有绑定 POST 请求(只是改了前端页面展示)

  • 如果看到:POST /api/employees 201

    但 Workbench 里查不到新增数据
    大概率:后端写入缺少 commit(201 不等于落库)

这些问题本质都在提醒:只有当表结构、接口契约、前端交互三者对齐,CRUD 才算真正跑通。


1.3 准备数据库:

我这里以一个常见场景------商场员工及顾客消费信息作为数据源 ,建立 MySQL 的 coffee 数据库(你也可以换成自己的业务)。

这里的SQL语句分别创建了branch(员工所属分支表) 、client(客户信息表)、employee(员工表)、work_with (连接员工和客户,并记员工的销售业绩。)四个表。

sql 复制代码
CREATE TABLE `branch` (
  `branch_id` int NOT NULL,
  `branch_name` varchar(20) DEFAULT NULL,
  `manager_id` int DEFAULT NULL,
  PRIMARY KEY (`branch_id`),
  KEY `manager_id` (`manager_id`),
  CONSTRAINT `branch_ibfk_1` FOREIGN KEY (`manager_id`) REFERENCES `employee` (`emp_id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
sql 复制代码
CREATE TABLE `client` (
  `client_id` int NOT NULL,
  `client_name` varchar(20) DEFAULT NULL,
  `phone_num` varchar(32) DEFAULT NULL,
  PRIMARY KEY (`client_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
sql 复制代码
CREATE TABLE `employee` (
  `emp_id` int NOT NULL,
  `name` varchar(20) DEFAULT NULL,
  `birth_date` date DEFAULT NULL,
  `sex` varchar(1) DEFAULT NULL,
  `salary` int DEFAULT NULL,
  `branch_id` int DEFAULT NULL,
  `sup_id` int DEFAULT NULL,
  PRIMARY KEY (`emp_id`),
  KEY `branch_id` (`branch_id`),
  KEY `sup_id` (`sup_id`),
  CONSTRAINT `employee_ibfk_1` FOREIGN KEY (`branch_id`) REFERENCES `branch` (`branch_id`) ON DELETE SET NULL,
  CONSTRAINT `employee_ibfk_2` FOREIGN KEY (`sup_id`) REFERENCES `employee` (`emp_id`) ON DELETE SET NULL
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;
sql 复制代码
CREATE TABLE `work_with` (
  `emp_id` int NOT NULL,
  `client_id` int NOT NULL,
  `total_sales` int DEFAULT NULL,
  PRIMARY KEY (`emp_id`,`client_id`),
  KEY `client_id` (`client_id`),
  CONSTRAINT `work_with_ibfk_1` FOREIGN KEY (`emp_id`) REFERENCES `employee` (`emp_id`) ON DELETE CASCADE,
  CONSTRAINT `work_with_ibfk_2` FOREIGN KEY (`client_id`) REFERENCES `client` (`client_id`) ON DELETE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

在 Python 准备连接数据库之前,建议先在 Workbench 执行三条自检:

sql 复制代码
SELECT DATABASE();
SHOW TABLES;
SELECT COUNT(*) FROM employee;

来确认当前连接的是哪个库、表是否存在,表里是否有数据。


二、前后端联动

2.1 文件 1:coffee_db.py(数据库连接与执行层)

这一层的职责是:

  • 提供连接数据库的条件(host/port/user/password/database/charset)

  • 封装执行 SQL 的方法

  • 写操作必须 commit;出错 rollback

注意:查询不需要 commit,只有 insert/update/delete(写)才需要。

1、 获取连接

python 复制代码
# coffee_db.py
import pymysql

def get_conn():
    return pymysql.Connection(
        host="127.0.0.1",
        port=3306,
        user="root",
        password="123456",
        database="coffee",
        charset="utf8mb4",
        cursorclass=pymysql.cursors.DictCursor,
        autocommit=False,  # 推荐:手动 commit 更可控
    )

2、 query:查(SELECT)→ 返回 rows

python 复制代码
# coffee_db.py
def query(sql, params=None):
    conn = get_conn()
    try:
        with conn.cursor() as cur:
            cur.execute(sql, params or ())
            return cur.fetchall()  # rows
    finally:
        conn.close()

3、 execute:写(INSERT/UPDATE/DELETE)→ 返回 affected_rows(并 commit)

python 复制代码
# coffee_db.py
def execute(sql, params=None):
    conn = get_conn()
    try:
        with conn.cursor() as cur:
            affected = cur.execute(sql, params or ())  # affected_rows
        conn.commit()   # 写操作必须提交
        return affected
    except:
        conn.rollback() # 出错撤销本次操作
        raise
    finally:
        conn.close()

你可以这样理解 DB 返回的两类结果:

  • rows:SELECT 查出来的多行数据(给前端表格渲染用)

  • affected_rows:写操作影响了多少行(判断是否真的生效)


2.2. 文件 2:coffee_admin.html(前端页面:按钮绑定 fetch)

最初我以为"写了表单 + 写了按钮 = 能写数据库",其实不对。
真正能写进数据库的关键是:按钮点击时必须发出 POST/PUT/DELETE 请求。

下面是示例:

1、 GET:加载 employees 列表

html 复制代码
<!-- templates/coffee_admin.html -->
<button id="btnRefresh">刷新 Employees</button>

<script>
async function loadEmployees() {
  const res = await fetch("/api/employees"); // GET
  const data = await res.json();
  console.log("employees:", data.data);
}

document.getElementById("btnRefresh").addEventListener("click", loadEmployees);
loadEmployees();
</script>

2、 POST:保存按钮绑定新增员工(核心)

html 复制代码
<button id="btnSave">保存(新增员工)</button>

<script>
document.getElementById("btnSave").addEventListener("click", async () => {
  const payload = {
    emp_id: 211,
    name: "小红",
    birth_date: "1999-02-01",
    sex: "F",
    salary: 30000,
    branch_id: 1,
    sup_id: 206
  };

  const res = await fetch("/api/employees", {
    method: "POST",
    headers: {"Content-Type":"application/json"},
    body: JSON.stringify(payload)
  });

  const data = await res.json();
  console.log("create result:", res.status, data);

  // 成功后刷新列表:关闭弹窗/提示 toast/重新 GET
  if (res.ok && data.ok) {
    await loadEmployees();
  }
});
</script>

你会看到这里的固定规律:

  • GET 查询:通常参数放在 URL query(?q=...),不需要 body

  • POST/PUT 写入:需要 JSON body,所以需要head中说明body中结构(比如head中是 Content-Type: application/json ,body中是: JSON.stringify(payload)

  • DELETE 删除:通常靠 URL 传 id


2.3 文件 3:coffee_app.py(Flask API:CRUD 真正发生)

先明确一个认识:

增删查改真正发生在后端(API 接口)里。

前端按钮本身不会直接操作 MySQL,它只是发 HTTP 请求(GET/POST/PUT/DELETE)。

Flask 的 API 文件通过路由"截获请求",解析 request,执行 SQL(或调用 db 层执行),再返回 JSON 响应。

可将整体交互链路理解为:

  • 前端按钮 = 触发请求(fetch发出请求)

  • API 路由 = 接收请求 + 执行业务(SQL)

  • 数据库 = 数据落点

1、 先让 Flask 能返回页面(否则你只会看到默认页)

python 复制代码
# coffee_app.py
from flask import Flask, request, jsonify, render_template
import coffee_db as db

app = Flask(__name__)

@app.get("/")  #截取路由地址,截取到"/"才执行后续代码。
def home():
    return render_template("coffee_admin.html")

2、 GET:支持 Query 参数筛选(q / branch_id)

python 复制代码
@app.get("/api/employees")
def list_employees():
    q = (request.args.get("q") or "").strip()
    branch_id = (request.args.get("branch_id") or "").strip()

    sql = """
    SELECT e.emp_id, e.name, e.birth_date, e.sex, e.salary, e.branch_id,
           b.branch_name, e.sup_id, s.name AS sup_name
    FROM employee e
    LEFT JOIN branch b ON e.branch_id=b.branch_id
    LEFT JOIN employee s ON e.sup_id=s.emp_id
    WHERE 1=1
    """
    params = []

    if q:
        sql += " AND (CAST(e.emp_id AS CHAR) LIKE %s OR e.name LIKE %s)"
        params += [f"%{q}%", f"%{q}%"]

    if branch_id:
        sql += " AND e.branch_id=%s"
        params += [branch_id]

    rows = db.query(sql, params)
    return jsonify({"ok": True, "data": rows})

对应前端调用:

html 复制代码
fetch("/api/employees?q=小黄&branch_id=1")

3、 POST:新增员工(request.get_json → INSERT → commit)

复制代码
@app.post("/api/employees")
def create_employee():
    body = request.get_json(force=True)

    sql = """
    INSERT INTO employee(emp_id, name, birth_date, sex, salary, branch_id, sup_id)
    VALUES (%s,%s,%s,%s,%s,%s,%s)
    """
    affected = db.execute(sql, (
        body["emp_id"], body["name"], body["birth_date"], body["sex"],
        body["salary"], body["branch_id"], body.get("sup_id")
    ))
    return jsonify({"ok": True, "data": {"affected": affected}}), 201

4、 启动服务

python 复制代码
if __name__ == "__main__":    #运行脚本,才能将服务器启动。
    app.run(host="127.0.0.1", port=5000, debug=True)

三、关系图示

四、 小结

最小可行打通其实就三件事:

  1. DB 层:能连库、能执行 SQL、写操作 commit

  2. API 层:路由匹配 method+path,解析 request,把 query/body 映射到 SQL

  3. 前端:按钮真的发出 POST/PUT/DELETE(而不是只改页面)

只要这三层对齐,你就能从"页面 demo"升级到"真实 CRUD 系统"。


光说不练是难以看到成效的,所以可以多多尝试,结合以上示例动手试试。欢迎你有任何的问题,在评论中与我讨论 ~

相关推荐
mr_LuoWei20092 小时前
自定义的中文脚本解释器来实现对excel自动化处理(二)
运维·python·自动化
梦想的旅途22 小时前
企微客户自动触达 API:实现全生命周期的自动化消息路由
数据库·自动化·企业微信
电商API_180079052472 小时前
企业级应用:京东商品详情 API 的高可用架构与多级缓存设计
开发语言·人工智能·python·数据分析·网络爬虫·php
shyの同学2 小时前
SQL 谓词下推带来的潜在问题
数据库·sql·mysql
x_lrong2 小时前
LangChain&Redis记忆
数据库·redis·langchain·向量数据库
代码探秘者2 小时前
【Redis】双写一致性:延迟双删 / 读写锁 / 异步通知 / Canal,一文全解
java·数据库·redis·后端·算法·缓存
witAI2 小时前
**即梦仿真人剧2025推荐,沉浸式情感交互新体验**据
python·交互
6+h2 小时前
【Java】JDK、JRE、JVM三者最通俗的讲解
java·jvm·python
西柚小萌新2 小时前
【数据库】--PostgreSQL 详细安装教程
数据库·postgresql