Skip to content

数据库设计 ​

本章详细描述项目的数据库设计,包括核心表结构、通用字段规范、ER 关系和命名约定。

设计原则

所有业务表继承 BaseModel 基类,自动获得 6 个通用字段(id / create_user / create_time / update_user / update_time / is_delete)。表名使用 DB_PREFIX 前缀(默认 flask_),软删除通过 is_delete 字段实现。

通用字段规范 ​

所有业务表共享以下通用字段,由 BaseModel 基类自动提供:

字段名类型约束默认值说明
idINTPRIMARY KEY, AUTO_INCREMENT—主键自增
create_userVARCHAR(50)NULLABLENULL创建人(realname)
create_timeDATETIMENOT NULLCURRENT_TIMESTAMP创建时间(UTC)
update_userVARCHAR(50)NULLABLENULL更新人(realname)
update_timeDATETIMENOT NULLCURRENT_TIMESTAMP更新时间(UTC,onupdate)
is_deleteINTNOT NULL, INDEX0软删除:0=正常,1=已删除

核心表结构 ​

系统管理模块 ​

用户表 flask_user ​

字段名类型约束说明
idINTPK用户ID
usernameVARCHAR(50)NOT NULL, UNIQUE登录账号
passwordVARCHAR(200)NOT NULL密码(bcrypt 哈希)
saltVARCHAR(50)NULLABLE密码盐值
realnameVARCHAR(50)NULLABLE真实姓名
avatarVARCHAR(500)NULLABLE头像地址
emailVARCHAR(100)NULLABLE邮箱
mobileVARCHAR(20)NULLABLE手机号
genderINTDEFAULT 0性别:0=未知 1=男 2=女
dept_idINTNULLABLE, INDEX部门ID
position_idINTNULLABLE, INDEX岗位ID
level_idINTNULLABLE, INDEX职级ID
statusINTDEFAULT 1状态:1=正常 2=禁用
create_userVARCHAR(50)NULLABLE通用字段
create_timeDATETIMEDEFAULT NOW()通用字段
update_userVARCHAR(50)NULLABLE通用字段
update_timeDATETIMEDEFAULT NOW()通用字段
is_deleteINTDEFAULT 0, INDEX通用字段

角色表 flask_role ​

字段名类型约束说明
idINTPK角色ID
nameVARCHAR(100)NOT NULL, INDEX角色名称
codeVARCHAR(100)NOT NULL, UNIQUE角色编码
statusINTDEFAULT 1状态:1=正常 2=禁用
sortINTDEFAULT 0排序
remarkVARCHAR(500)NULLABLE备注
+ 通用字段

菜单表 flask_menu ​

字段名类型约束说明
idINTPK菜单ID
parent_idINTDEFAULT 0, INDEX父菜单ID(0=顶级)
nameVARCHAR(100)NOT NULL菜单名称
typeINTNOT NULL类型:1=目录 2=菜单 3=按钮
pathVARCHAR(200)NULLABLE路由路径
componentVARCHAR(200)NULLABLE前端组件路径
permissionVARCHAR(200)NULLABLE权限标识(如 sys:user:add)
iconVARCHAR(100)NULLABLE菜单图标
sortINTDEFAULT 0排序
visibleINTDEFAULT 1是否可见:1=是 2=否
statusINTDEFAULT 1状态:1=正常 2=禁用
+ 通用字段

部门表 flask_dept ​

字段名类型约束说明
idINTPK部门ID
parent_idINTDEFAULT 0, INDEX父部门ID(0=顶级)
nameVARCHAR(100)NOT NULL部门名称
leaderVARCHAR(50)NULLABLE负责人
mobileVARCHAR(20)NULLABLE联系电话
emailVARCHAR(100)NULLABLE邮箱
sortINTDEFAULT 0排序
statusINTDEFAULT 1状态:1=正常 2=禁用
+ 通用字段

岗位表 flask_position ​

字段名类型约束说明
idINTPK岗位ID
nameVARCHAR(255)NOT NULL, INDEX岗位名称
statusINTDEFAULT 0, INDEX状态:1=在用 2=停用
sortINTDEFAULT 0排序
+ 通用字段

职级表 flask_level ​

字段名类型约束说明
idINTPK职级ID
nameVARCHAR(255)NOT NULL, INDEX职级名称
statusINTDEFAULT 0, INDEX状态:1=在用 2=停用
sortINTDEFAULT 0排序
+ 通用字段

关联表 ​

用户角色关联表 flask_user_role ​

字段名类型约束说明
idINTPK主键
user_idINTNOT NULL, INDEX用户ID
role_idINTNOT NULL, INDEX角色ID
+ 通用字段

角色菜单关联表 flask_role_menu ​

字段名类型约束说明
idINTPK主键
role_idINTNOT NULL, INDEX角色ID
menu_idINTNOT NULL, INDEX菜单ID
+ 通用字段

数据字典模块 ​

字典表 flask_dict ​

字段名类型约束说明
idINTPK字典ID
nameVARCHAR(200)NOT NULL字典名称
codeVARCHAR(200)NOT NULL, UNIQUE字典编码
statusINTDEFAULT 1状态
remarkVARCHAR(500)NULLABLE备注
+ 通用字段

字典项表 flask_dict_item ​

字段名类型约束说明
idINTPK字典项ID
dict_codeVARCHAR(200)NOT NULL, INDEX所属字典编码
labelVARCHAR(200)NOT NULL显示名
valueVARCHAR(200)NOT NULL字典值
sortINTDEFAULT 0排序
statusINTDEFAULT 1状态
remarkVARCHAR(500)NULLABLE备注
+ 通用字段

内容管理模块 ​

文章表 flask_article ​

字段名类型约束说明
idINTPK文章ID
category_idINTNULLABLE, INDEX分类ID
titleVARCHAR(200)NOT NULL文章标题
coverVARCHAR(500)NULLABLE封面图片
summaryVARCHAR(500)NULLABLE摘要
contentTEXTNULLABLE正文(富文本)
authorVARCHAR(50)NULLABLE作者
sourceVARCHAR(200)NULLABLE来源
view_countINTDEFAULT 0浏览次数
is_topINTDEFAULT 0是否置顶
statusINTDEFAULT 1状态
sortINTDEFAULT 0排序
+ 通用字段

文章分类表 flask_category ​

字段名类型约束说明
idINTPK分类ID
parent_idINTDEFAULT 0, INDEX父分类ID
nameVARCHAR(100)NOT NULL分类名称
sortINTDEFAULT 0排序
statusINTDEFAULT 1状态
+ 通用字段

通知公告表 flask_notice ​

字段名类型约束说明
idINTPK通知ID
titleVARCHAR(200)NOT NULL标题
contentTEXTNULLABLE内容
typeINTDEFAULT 1类型:1=通知 2=公告
statusINTDEFAULT 1状态
+ 通用字段

日志模块 ​

登录日志表 flask_login_log ​

字段名类型约束说明
idINTPK日志ID
usernameVARCHAR(50)NULLABLE登录账号
ipVARCHAR(50)NULLABLE登录IP
locationVARCHAR(200)NULLABLE登录地点
browserVARCHAR(100)NULLABLE浏览器
osVARCHAR(100)NULLABLE操作系统
statusINTDEFAULT 1状态:1=成功 2=失败
msgVARCHAR(500)NULLABLE提示消息
+ 通用字段

操作日志表 flask_operation_log ​

字段名类型约束说明
idINTPK日志ID
usernameVARCHAR(50)NULLABLE操作人
moduleVARCHAR(100)NULLABLE操作模块
actionVARCHAR(100)NULLABLE操作动作
methodVARCHAR(10)NULLABLE请求方法
urlVARCHAR(500)NULLABLE请求URL
paramsTEXTNULLABLE请求参数
ipVARCHAR(50)NULLABLE操作IP
statusINTDEFAULT 1状态
durationINTNULLABLE耗时(毫秒)
+ 通用字段

定时任务模块 ​

任务表 flask_job ​

字段名类型约束说明
idINTPK任务ID
nameVARCHAR(200)NOT NULL任务名称
job_groupVARCHAR(100)NULLABLE任务分组
invoke_targetVARCHAR(500)NOT NULL调用目标
cron_expressionVARCHAR(200)NOT NULLCron 表达式
misfire_policyINTDEFAULT 3执行策略
concurrentINTDEFAULT 0是否并发
statusINTDEFAULT 1状态:1=运行 2=暂停
remarkVARCHAR(500)NULLABLE备注
+ 通用字段

任务日志表 flask_job_log ​

字段名类型约束说明
idINTPK日志ID
job_idINTNOT NULL, INDEX任务ID
job_nameVARCHAR(200)NULLABLE任务名称
invoke_targetVARCHAR(500)NULLABLE调用目标
job_messageVARCHAR(500)NULLABLE执行结果
statusINTDEFAULT 1状态
exception_infoTEXTNULLABLE异常信息
start_timeDATETIMENULLABLE开始时间
end_timeDATETIMENULLABLE结束时间
+ 通用字段

ER 关系图 ​

┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│   flask      │ │   flask      │ │   flask      │
│   _user      │ │   _user_role │ │   _role      │
│──────────────│ │──────────────│ │──────────────│
│ id (PK)      │←───│ user_id (FK) │ │ id (PK)      │
│ username     │ │ role_id (FK) │───→│ name         │
│ password     │ └──────────────┘ │ code         │
│ realname     │ └──────┬───────┘
│ dept_id (FK) │───→┌──────────────┐ │
│ position_id  │ │   flask      │ │
│ (FK)         │ │   _dept      │ │
│ level_id (FK)│ │──────────────│ │
│              │ │ id (PK)      │ │
│              │ │ parent_id    │ │
│              │ │ name         │ │
│              │ └──────────────┘ │
│              │                  │
│              │ ┌──────────────┐ │
│              │ │   flask      │ │
│              │ │   _role_menu │ │
│              │ │──────────────│ │
│              │ │ role_id (FK) │←───────────┘
│              │ │ menu_id (FK) │───→┌──────────────┐
│              │ └──────────────┘ │   flask      │
└──────────────┘                  │   _menu      │
                                  │──────────────│
┌──────────────┐                  │ id (PK)      │
│   flask      │                  │ parent_id    │
│   _position  │                  │ name         │
│──────────────│                  │ permission   │
│ id (PK)      │                  │ type         │
│ name         │                  └──────────────┘
└──────────────┘

┌──────────────┐ ┌──────────────┐ ┌──────────────┐
│   flask      │ │   flask      │ │   flask      │
│   _dict      │ │   _dict_item │ │   _config    │
│──────────────│ │──────────────│ │──────────────│
│ id (PK)      │←───│ dict_code    │ │ id (PK)      │
│ name         │ │ label        │ │ name         │
│ code         │ │ value        │ │ code         │
└──────────────┘ └──────────────┘ └──────────────┘

┌──────────────┐ ┌──────────────┐
│   flask      │ │   flask      │
│   _article   │ │   _category  │
│──────────────│ │──────────────│
│ id (PK)      │ │ id (PK)      │
│ category_id  │───→│ parent_id    │
│ title        │ │ name         │
│ content      │ └──────────────┘
└──────────────┘

命名约定 ​

约定项规范示例
表名{DB_PREFIX}{module_name}flask_position
字段名小写下划线(snake_case)create_user、dict_code
主键id,INT,AUTO_INCREMENT—
外键{关联表名}_iduser_id、dept_id
索引外键字段、高频查询字段status、username
布尔状态INT 类型,0/1 或 1/2is_delete: 0/1、status: 1/2
时间字段DATETIME 类型create_time、update_time

外键约束

不使用数据库层面的外键约束(FOREIGN KEY),而是通过应用层代码维护引用完整性。这样做的好处是:简化跨库迁移、避免级联删除风险、提升写入性能。删除关联数据时,由 Service 层的 before_delete 钩子检查引用关系。

多数据库驱动支持 ​

通过 DB_DRIVER 环境变量切换数据库驱动,config/database.py 的 _build_database_url() 函数按驱动构建方言感知的 SQLAlchemy 引擎:

驱动DB_DRIVER连接 URL 格式特殊处理
MySQLmysql(默认)mysql+pymysql://user:pass@host:3306/dbCLIENT.FOUND_ROWS 避免重复提交时 rowcount=0 误判
PostgreSQLpostgresqlpostgresql+psycopg://user:pass@host:5432/dboptions="-c timezone=UTC" 确保 naive UTC 一致
SQL Servermssqlmssql+pymssql://user:pass@host:1433/dblogin_timeout 连接超时
SQLitesqlitesqlite:///./db.sqlite3check_same_thread=False,跳过连接池参数
Oracleoracleoracle+oracledb://user:pass@host:1521/dbthin 模式,UTF-8 编码

业务代码无需修改,SQLAlchemy 自动处理方言差异(如分页语法、自增策略等)。

请求级会话管理 ​

Flask 使用 g 对象和 before_request / after_request 钩子管理数据库会话:

python
# src/middleware/transaction.py
from flask import request, g
from src.core.database import db

def register_transaction(app):
    @app.before_request
    def _transaction_begin():
        g.transaction_active = True

    @app.after_request
    def _transaction_commit(response):
        if request.method in ('POST', 'PUT', 'DELETE', 'PATCH'):
            if response.status_code == 200:
                body = response.get_json()
                if body and body.get('code') == 0:
                    db.session.commit()
                else:
                    db.session.rollback()
        return response

    @app.teardown_request
    def _transaction_rollback(exception):
        if exception:
            db.session.rollback()
        db.session.remove()

约束命名约定

database.py 中定义了自定义约束命名约定,索引前缀使用 idx_ 而非默认的 ix_:

python
convention = {
    "ix": "idx_%(table_name)s_%(column_0_name)s",
    "uq": "uq_%(table_name)s_%(column_0_name)s",
    "ck": "ck_%(table_name)s_%(constraint_name)s",
    "fk": "fk_%(table_name)s_%(column_0_name)s_%(referred_table_name)s",
    "pk": "pk_%(table_name)s",
}
metadata = MetaData(naming_convention=convention)
Base = declarative_base(metadata=metadata)

总结 ​

数据库设计以「通用字段 + 软删除 + 应用层外键」为核心策略。所有业务表继承 BaseModel 获得统一的通用字段,通过 is_delete 实现软删除,通过应用层代码维护引用完整性。核心表覆盖系统管理(用户/角色/菜单/部门/岗位/职级)、数据字典、内容管理(文章/分类/通知)、日志管理、定时任务等功能域。多数据库驱动通过 config/database.py 的 _build_database_url() 按方言构建引擎,业务代码与具体数据库解耦。请求级会话通过 Flask 的 g 对象和 before_request / after_request 钩子实现,审计数据可通过 commit_independently() 绕过请求事务独立提交。

小蚂蚁云团队 · 提供技术支持