第1章:数据库设计与建模——工单表结构设计与SQLite集成
各位同学,欢迎来到《客户服务工单系统开发实战》的第一章。
今天咱们要聊的,是整个系统的地基——数据库设计。说白了,就是工单长什么样,数据怎么存。我做了这么多年项目,见过太多系统上线后改表结构的惨案。所以这一章,咱们把地基打牢。
1.1 工单表结构设计——先想清楚再动手
工单系统最核心的,就是工单本身。你想想看,一张工单需要记录什么?
我个人习惯,先列业务需求,再定字段。一个客服工单,至少要有:
- 唯一标识:ticket_id,每张工单的身份证
- 标题:title,用户一眼能看到的问题概要
- 描述:description,详细内容,可能很长
- 状态:status,比如待处理、处理中、已关闭
- 优先级:priority,紧急、高、中、低
- 时间戳:create_time 和 update_time,记录生命周期
嗯,这里要注意。我在项目中遇到过,有人把时间戳只存了一个,结果排查问题时根本不知道什么时候更新的。所以,创建时间和更新时间,一个都不能少。
来看一下具体的字段设计表:
| 字段名 | 类型 | 说明 | 约束 |
|---|---|---|---|
| ticket_id | INTEGER | 工单唯一编号 | 主键,自增 |
| title | VARCHAR(200) | 工单标题 | 非空 |
| description | TEXT | 工单详细描述 | 可空 |
| status | VARCHAR(20) | 当前状态 | 默认 'open' |
| priority | VARCHAR(10) | 优先级 | 默认 'medium' |
| create_time | DATETIME | 创建时间 | 自动生成 |
| update_time | DATETIME | 最后更新时间 | 自动更新 |
核心要点:status 和 priority 建议用字符串,而不是数字。为什么?因为代码里一眼就能看出含义,不用查字典。我曾经接手过一个项目,状态用 0、1、2 表示,每次都要翻文档,太痛苦了。
1.2 SQLite数据库创建——轻量级的选择
为什么选 SQLite?说白了,咱们这是教学项目,不想让大家折腾安装 MySQL 或 PostgreSQL。SQLite 就是一个文件,零配置,开箱即用。
但别小看它。我在一些小工具、原型验证项目里,经常用 SQLite。性能足够,而且部署简单。等系统真到了需要高并发的阶段,再迁移到 MySQL 也不迟。
创建 SQLite 数据库,其实就一行命令的事。但咱们用 Flask-SQLAlchemy,会更优雅。
小提示:SQLite 的数据库文件默认会生成在你的项目根目录下。建议在 config.py 里配置路径,方便后续迁移。
1.3 Flask-SQLAlchemy集成——让数据库操作变简单
Flask-SQLAlchemy 是 Flask 和 SQLAlchemy 的桥梁。SQLAlchemy 是 Python 里最强大的 ORM 框架,没有之一。ORM 是什么?就是让你用 Python 对象操作数据库,不用写原生 SQL。
我刚开始学的时候也觉得 ORM 多此一举,直到有一次要改表结构,几十条 SQL 语句要同步修改……嗯,从那以后我就老老实实用 ORM 了。
来看集成步骤:
- 安装依赖包
- 配置数据库 URI
- 初始化 SQLAlchemy 对象
- 定义模型类
- 创建表
先安装必要的包:
pip install flask flask-sqlalchemy
然后在 app.py 中配置:
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
from datetime import datetime
app = Flask(__name__)
# 配置数据库路径,/// 表示相对路径
app.config['SQLALCHEMY_DATABASE_URI'] = 'sqlite:///tickets.db'
app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
db = SQLAlchemy(app)
接下来,定义我们的工单模型。这就是把刚才的表结构,用 Python 类表达出来:
class Ticket(db.Model):
__tablename__ = 'tickets'
ticket_id = db.Column(db.Integer, primary_key=True, autoincrement=True)
title = db.Column(db.String(200), nullable=False)
description = db.Column(db.Text, nullable=True)
status = db.Column(db.String(20), default='open')
priority = db.Column(db.String(10), default='medium')
create_time = db.Column(db.DateTime, default=datetime.utcnow)
update_time = db.Column(db.DateTime, default=datetime.utcnow, onupdate=datetime.utcnow)
def __repr__(self):
return f'<Ticket {self.ticket_id}: {self.title}>'
注意:onupdate=datetime.utcnow 这个参数,很多人会漏掉。它的作用是:每次更新记录时,自动把 update_time 改成当前时间。没有它,你就得手动维护这个字段,很容易出错。
最后,创建表。在 Python 交互环境或应用启动时执行:
with app.app_context():
db.create_all()
执行完后,你会看到项目目录下多了一个 tickets.db 文件。没错,这就是你的数据库。
1.4 验证一下——写点测试数据
光建表不行,得试试能不能用。我习惯写个小脚本验证:
from app import app, db, Ticket
from datetime import datetime
with app.app_context():
# 创建一张测试工单
ticket = Ticket(
title='无法登录系统',
description='用户反馈输入密码后提示"账号异常",已尝试重置密码无效',
status='open',
priority='high'
)
db.session.add(ticket)
db.session.commit()
# 查询所有工单
tickets = Ticket.query.all()
for t in tickets:
print(f'工单 #{t.ticket_id}: {t.title} - {t.status}')
运行后,如果看到输出 工单 #1: 无法登录系统 - open,恭喜你,数据库已经跑通了。
避坑指南:我曾经犯过一个低级错误——在创建表之前忘了执行 with app.app_context(),结果报错说「没有应用上下文」。记住,Flask-SQLAlchemy 的所有操作,都需要在应用上下文中进行。
1.5 本章小结
这一章,咱们完成了三件事:
- 设计了工单表的核心字段结构
- 创建了 SQLite 数据库文件
- 集成了 Flask-SQLAlchemy,并定义了 Ticket 模型
说白了,就是给工单系统搭好了数据库架子。下一章,咱们会在这个架子上,搭建 RESTful API,让前端能真正操作这些数据。
记住一句话:数据库设计是系统的灵魂。现在多花一分钟想清楚,后面能省一小时改代码。
好,这一章就到这儿。有问题随时交流。