数据库设计
本章详细描述项目的数据库设计,包括核心表结构、通用字段规范、ER 关系和命名约定。
:::tip 设计原则
所有业务表继承 BaseModel 基类,自动获得 6 个通用字段(id / create_user / create_time / update_user / update_time / is_delete)。表名使用 DB_PREFIX 前缀(默认 flask_),软删除通过 is_delete 字段实现。
:::
通用字段规范
所有业务表共享以下通用字段,由 BaseModel 基类自动提供:
| 字段名 |
类型 |
约束 |
默认值 |
说明 |
id |
INT |
PRIMARY KEY, AUTO_INCREMENT |
— |
主键自增 |
create_user |
VARCHAR(50) |
NULLABLE |
NULL |
创建人(realname) |
create_time |
DATETIME |
NOT NULL |
CURRENT_TIMESTAMP |
创建时间(UTC) |
update_user |
VARCHAR(50) |
NULLABLE |
NULL |
更新人(realname) |
update_time |
DATETIME |
NOT NULL |
CURRENT_TIMESTAMP |
更新时间(UTC,onupdate) |
is_delete |
INT |
NOT NULL, INDEX |
0 |
软删除:0=正常,1=已删除 |
核心表结构
系统管理模块
用户表 flask_user
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
用户ID |
| username |
VARCHAR(50) |
NOT NULL, UNIQUE |
登录账号 |
| password |
VARCHAR(200) |
NOT NULL |
密码(bcrypt 哈希) |
| salt |
VARCHAR(50) |
NULLABLE |
密码盐值 |
| realname |
VARCHAR(50) |
NULLABLE |
真实姓名 |
| avatar |
VARCHAR(500) |
NULLABLE |
头像地址 |
| email |
VARCHAR(100) |
NULLABLE |
邮箱 |
| mobile |
VARCHAR(20) |
NULLABLE |
手机号 |
| gender |
INT |
DEFAULT 0 |
性别:0=未知 1=男 2=女 |
| dept_id |
INT |
NULLABLE, INDEX |
部门ID |
| position_id |
INT |
NULLABLE, INDEX |
岗位ID |
| level_id |
INT |
NULLABLE, INDEX |
职级ID |
| status |
INT |
DEFAULT 1 |
状态:1=正常 2=禁用 |
| create_user |
VARCHAR(50) |
NULLABLE |
通用字段 |
| create_time |
DATETIME |
DEFAULT NOW() |
通用字段 |
| update_user |
VARCHAR(50) |
NULLABLE |
通用字段 |
| update_time |
DATETIME |
DEFAULT NOW() |
通用字段 |
| is_delete |
INT |
DEFAULT 0, INDEX |
通用字段 |
角色表 flask_role
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
角色ID |
| name |
VARCHAR(100) |
NOT NULL, INDEX |
角色名称 |
| code |
VARCHAR(100) |
NOT NULL, UNIQUE |
角色编码 |
| status |
INT |
DEFAULT 1 |
状态:1=正常 2=禁用 |
| sort |
INT |
DEFAULT 0 |
排序 |
| remark |
VARCHAR(500) |
NULLABLE |
备注 |
| + 通用字段 |
|
|
|
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
菜单ID |
| parent_id |
INT |
DEFAULT 0, INDEX |
父菜单ID(0=顶级) |
| name |
VARCHAR(100) |
NOT NULL |
菜单名称 |
| type |
INT |
NOT NULL |
类型:1=目录 2=菜单 3=按钮 |
| path |
VARCHAR(200) |
NULLABLE |
路由路径 |
| component |
VARCHAR(200) |
NULLABLE |
前端组件路径 |
| permission |
VARCHAR(200) |
NULLABLE |
权限标识(如 sys:user:add) |
| icon |
VARCHAR(100) |
NULLABLE |
菜单图标 |
| sort |
INT |
DEFAULT 0 |
排序 |
| visible |
INT |
DEFAULT 1 |
是否可见:1=是 2=否 |
| status |
INT |
DEFAULT 1 |
状态:1=正常 2=禁用 |
| + 通用字段 |
|
|
|
部门表 flask_dept
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
部门ID |
| parent_id |
INT |
DEFAULT 0, INDEX |
父部门ID(0=顶级) |
| name |
VARCHAR(100) |
NOT NULL |
部门名称 |
| leader |
VARCHAR(50) |
NULLABLE |
负责人 |
| mobile |
VARCHAR(20) |
NULLABLE |
联系电话 |
| email |
VARCHAR(100) |
NULLABLE |
邮箱 |
| sort |
INT |
DEFAULT 0 |
排序 |
| status |
INT |
DEFAULT 1 |
状态:1=正常 2=禁用 |
| + 通用字段 |
|
|
|
岗位表 flask_position
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
岗位ID |
| name |
VARCHAR(255) |
NOT NULL, INDEX |
岗位名称 |
| status |
INT |
DEFAULT 0, INDEX |
状态:1=在用 2=停用 |
| sort |
INT |
DEFAULT 0 |
排序 |
| + 通用字段 |
|
|
|
职级表 flask_level
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
职级ID |
| name |
VARCHAR(255) |
NOT NULL, INDEX |
职级名称 |
| status |
INT |
DEFAULT 0, INDEX |
状态:1=在用 2=停用 |
| sort |
INT |
DEFAULT 0 |
排序 |
| + 通用字段 |
|
|
|
关联表
用户角色关联表 flask_user_role
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
主键 |
| user_id |
INT |
NOT NULL, INDEX |
用户ID |
| role_id |
INT |
NOT NULL, INDEX |
角色ID |
| + 通用字段 |
|
|
|
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
主键 |
| role_id |
INT |
NOT NULL, INDEX |
角色ID |
| menu_id |
INT |
NOT NULL, INDEX |
菜单ID |
| + 通用字段 |
|
|
|
数据字典模块
字典表 flask_dict
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
字典ID |
| name |
VARCHAR(200) |
NOT NULL |
字典名称 |
| code |
VARCHAR(200) |
NOT NULL, UNIQUE |
字典编码 |
| status |
INT |
DEFAULT 1 |
状态 |
| remark |
VARCHAR(500) |
NULLABLE |
备注 |
| + 通用字段 |
|
|
|
字典项表 flask_dict_item
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
字典项ID |
| dict_code |
VARCHAR(200) |
NOT NULL, INDEX |
所属字典编码 |
| label |
VARCHAR(200) |
NOT NULL |
显示名 |
| value |
VARCHAR(200) |
NOT NULL |
字典值 |
| sort |
INT |
DEFAULT 0 |
排序 |
| status |
INT |
DEFAULT 1 |
状态 |
| remark |
VARCHAR(500) |
NULLABLE |
备注 |
| + 通用字段 |
|
|
|
内容管理模块
文章表 flask_article
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
文章ID |
| category_id |
INT |
NULLABLE, INDEX |
分类ID |
| title |
VARCHAR(200) |
NOT NULL |
文章标题 |
| cover |
VARCHAR(500) |
NULLABLE |
封面图片 |
| summary |
VARCHAR(500) |
NULLABLE |
摘要 |
| content |
TEXT |
NULLABLE |
正文(富文本) |
| author |
VARCHAR(50) |
NULLABLE |
作者 |
| source |
VARCHAR(200) |
NULLABLE |
来源 |
| view_count |
INT |
DEFAULT 0 |
浏览次数 |
| is_top |
INT |
DEFAULT 0 |
是否置顶 |
| status |
INT |
DEFAULT 1 |
状态 |
| sort |
INT |
DEFAULT 0 |
排序 |
| + 通用字段 |
|
|
|
文章分类表 flask_category
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
分类ID |
| parent_id |
INT |
DEFAULT 0, INDEX |
父分类ID |
| name |
VARCHAR(100) |
NOT NULL |
分类名称 |
| sort |
INT |
DEFAULT 0 |
排序 |
| status |
INT |
DEFAULT 1 |
状态 |
| + 通用字段 |
|
|
|
通知公告表 flask_notice
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
通知ID |
| title |
VARCHAR(200) |
NOT NULL |
标题 |
| content |
TEXT |
NULLABLE |
内容 |
| type |
INT |
DEFAULT 1 |
类型:1=通知 2=公告 |
| status |
INT |
DEFAULT 1 |
状态 |
| + 通用字段 |
|
|
|
日志模块
登录日志表 flask_login_log
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
日志ID |
| username |
VARCHAR(50) |
NULLABLE |
登录账号 |
| ip |
VARCHAR(50) |
NULLABLE |
登录IP |
| location |
VARCHAR(200) |
NULLABLE |
登录地点 |
| browser |
VARCHAR(100) |
NULLABLE |
浏览器 |
| os |
VARCHAR(100) |
NULLABLE |
操作系统 |
| status |
INT |
DEFAULT 1 |
状态:1=成功 2=失败 |
| msg |
VARCHAR(500) |
NULLABLE |
提示消息 |
| + 通用字段 |
|
|
|
操作日志表 flask_operation_log
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
日志ID |
| username |
VARCHAR(50) |
NULLABLE |
操作人 |
| module |
VARCHAR(100) |
NULLABLE |
操作模块 |
| action |
VARCHAR(100) |
NULLABLE |
操作动作 |
| method |
VARCHAR(10) |
NULLABLE |
请求方法 |
| url |
VARCHAR(500) |
NULLABLE |
请求URL |
| params |
TEXT |
NULLABLE |
请求参数 |
| ip |
VARCHAR(50) |
NULLABLE |
操作IP |
| status |
INT |
DEFAULT 1 |
状态 |
| duration |
INT |
NULLABLE |
耗时(毫秒) |
| + 通用字段 |
|
|
|
定时任务模块
任务表 flask_job
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
任务ID |
| name |
VARCHAR(200) |
NOT NULL |
任务名称 |
| job_group |
VARCHAR(100) |
NULLABLE |
任务分组 |
| invoke_target |
VARCHAR(500) |
NOT NULL |
调用目标 |
| cron_expression |
VARCHAR(200) |
NOT NULL |
Cron 表达式 |
| misfire_policy |
INT |
DEFAULT 3 |
执行策略 |
| concurrent |
INT |
DEFAULT 0 |
是否并发 |
| status |
INT |
DEFAULT 1 |
状态:1=运行 2=暂停 |
| remark |
VARCHAR(500) |
NULLABLE |
备注 |
| + 通用字段 |
|
|
|
任务日志表 flask_job_log
| 字段名 |
类型 |
约束 |
说明 |
| id |
INT |
PK |
日志ID |
| job_id |
INT |
NOT NULL, INDEX |
任务ID |
| job_name |
VARCHAR(200) |
NULLABLE |
任务名称 |
| invoke_target |
VARCHAR(500) |
NULLABLE |
调用目标 |
| job_message |
VARCHAR(500) |
NULLABLE |
执行结果 |
| status |
INT |
DEFAULT 1 |
状态 |
| exception_info |
TEXT |
NULLABLE |
异常信息 |
| start_time |
DATETIME |
NULLABLE |
开始时间 |
| end_time |
DATETIME |
NULLABLE |
结束时间 |
| + 通用字段 |
|
|
|
ER 关系图
命名约定
| 约定项 |
规范 |
示例 |
| 表名 |
{DB_PREFIX}{module_name} |
flask_position |
| 字段名 |
小写下划线(snake_case) |
create_user、dict_code |
| 主键 |
id,INT,AUTO_INCREMENT |
— |
| 外键 |
{关联表名}_id |
user_id、dept_id |
| 索引 |
外键字段、高频查询字段 |
status、username |
| 布尔状态 |
INT 类型,0/1 或 1/2 |
is_delete: 0/1、status: 1/2 |
| 时间字段 |
DATETIME 类型 |
create_time、update_time |
:::warning 外键约束
不使用数据库层面的外键约束(FOREIGN KEY),而是通过应用层代码维护引用完整性。这样做的好处是:简化跨库迁移、避免级联删除风险、提升写入性能。删除关联数据时,由 Service 层的 before_delete 钩子检查引用关系。
:::
多数据库驱动支持
通过 DB_DRIVER 环境变量切换数据库驱动,config/database.py 的 _build_database_url() 函数按驱动构建方言感知的 SQLAlchemy 引擎:
| 驱动 |
DB_DRIVER |
连接 URL 格式 |
特殊处理 |
| MySQL |
mysql(默认) |
mysql+pymysql://user:pass@host:3306/db |
CLIENT.FOUND_ROWS 避免重复提交时 rowcount=0 误判 |
| PostgreSQL |
postgresql |
postgresql+psycopg://user:pass@host:5432/db |
options="-c timezone=UTC" 确保 naive UTC 一致 |
| SQL Server |
mssql |
mssql+pymssql://user:pass@host:1433/db |
login_timeout 连接超时 |
| SQLite |
sqlite |
sqlite:///./db.sqlite3 |
check_same_thread=False,跳过连接池参数 |
| Oracle |
oracle |
oracle+oracledb://user:pass@host:1521/db |
thin 模式,UTF-8 编码 |
业务代码无需修改,SQLAlchemy 自动处理方言差异(如分页语法、自增策略等)。
请求级会话管理
Flask 使用 g 对象和 before_request / after_request 钩子管理数据库会话:
:::tip 约束命名约定
database.py 中定义了自定义约束命名约定,索引前缀使用 idx_ 而非默认的 ix_:
:::
总结
数据库设计以「通用字段 + 软删除 + 应用层外键」为核心策略。所有业务表继承 BaseModel 获得统一的通用字段,通过 is_delete 实现软删除,通过应用层代码维护引用完整性。核心表覆盖系统管理(用户/角色/菜单/部门/岗位/职级)、数据字典、内容管理(文章/分类/通知)、日志管理、定时任务等功能域。多数据库驱动通过 config/database.py 的 _build_database_url() 按方言构建引擎,业务代码与具体数据库解耦。请求级会话通过 Flask 的 g 对象和 before_request / after_request 钩子实现,审计数据可通过 commit_independently() 绕过请求事务独立提交。