18 KiB
18 KiB
模型验证规则
**本文档引用的文件** - [backend/app/models/models.py](file://backend/app/models/models.py) - [backend/app/models/finance.py](file://backend/app/models/finance.py) - [backend/app/schemas/schemas.py](file://backend/app/schemas/schemas.py) - [backend/app/api/v1/staff.py](file://backend/app/api/v1/staff.py) - [backend/app/api/v1/indicators.py](file://backend/app/api/v1/indicators.py) - [backend/app/api/v1/assessments.py](file://backend/app/api/v1/assessments.py) - [backend/app/services/staff_service.py](file://backend/app/services/staff_service.py) - [backend/app/services/indicator_service.py](file://backend/app/services/indicator_service.py) - [backend/app/services/assessment_service.py](file://backend/app/services/assessment_service.py) - [backend/app/main.py](file://backend/app/main.py) - [backend/requirements.txt](file://backend/requirements.txt)目录
简介
本文件系统性梳理了医院绩效系统中的模型验证规则,涵盖数据模型的验证机制,包括字段类型验证、范围限制、格式检查和业务规则验证。文档重点解释了以下三个层面的验证实现:
- Pydantic 模型验证:通过 Pydantic 的 Field 参数与类型注解实现请求体与响应体的数据校验。
- SQLAlchemy 约束验证:通过数据库层的列类型、索引与 CheckConstraint 实现数据完整性约束。
- 业务逻辑验证:通过服务层与 API 层的业务规则检查,确保数据在业务语义上的正确性。
同时,文档阐述了验证错误的处理方式与用户友好的错误信息设计,并提供验证规则的扩展方法与自定义验证器的实现建议。
项目结构
后端采用 FastAPI + SQLAlchemy 异步 ORM 的架构,数据模型位于 models 目录,Pydantic 数据模式位于 schemas 目录,API 路由位于 api/v1 目录,业务逻辑位于 services 目录,异常处理与全局配置位于 main.py。
graph TB
subgraph "API 层"
A1["staff.py"]
A2["indicators.py"]
A3["assessments.py"]
end
subgraph "服务层"
S1["staff_service.py"]
S2["indicator_service.py"]
S3["assessment_service.py"]
end
subgraph "模式层"
P1["schemas.py"]
end
subgraph "模型层"
M1["models.py"]
M2["finance.py"]
end
subgraph "核心"
C1["main.py"]
C2["requirements.txt"]
end
A1 --> S1
A2 --> S2
A3 --> S3
S1 --> M1
S2 --> M1
S3 --> M1
A1 --> P1
A2 --> P1
A3 --> P1
M1 --> C2
M2 --> C2
P1 --> C2
C1 --> A1
C1 --> A2
C1 --> A3
图表来源
- backend/app/api/v1/staff.py
- backend/app/api/v1/indicators.py
- backend/app/api/v1/assessments.py
- backend/app/services/staff_service.py
- backend/app/services/indicator_service.py
- backend/app/services/assessment_service.py
- backend/app/schemas/schemas.py
- backend/app/models/models.py
- backend/app/models/finance.py
- backend/app/main.py
- backend/requirements.txt
章节来源
- backend/app/api/v1/staff.py
- backend/app/api/v1/indicators.py
- backend/app/api/v1/assessments.py
- backend/app/services/staff_service.py
- backend/app/services/indicator_service.py
- backend/app/services/assessment_service.py
- backend/app/schemas/schemas.py
- backend/app/models/models.py
- backend/app/models/finance.py
- backend/app/main.py
- backend/requirements.txt
核心组件
- Pydantic 数据模式:通过 Field 的类型、长度、数值范围、正则表达式等参数实现字段级验证;通过枚举类型保证取值域的正确性;通过 model_config 的 from_attributes 控制 ORM 对象到 Pydantic 模式的转换。
- SQLAlchemy 模型:通过列类型(String、Integer、Numeric、Boolean、DateTime、Enum)、索引与 CheckConstraint 实现数据库层约束;通过外键关系与级联策略保证参照完整性。
- API 层:在路由函数中接收 Pydantic 模式作为请求体,自动触发 Pydantic 验证;在业务逻辑允许范围内进行额外的业务规则检查,并抛出 HTTP 异常。
- 服务层:封装 CRUD 与业务逻辑,负责数据一致性与业务规则的执行;在必要时进行跨实体的约束检查。
- 异常处理:全局注册异常处理器,捕获并记录验证错误与业务异常,返回统一的错误信息。
章节来源
- backend/app/schemas/schemas.py
- backend/app/models/models.py
- backend/app/models/finance.py
- backend/app/api/v1/staff.py
- backend/app/services/staff_service.py
- backend/app/main.py
架构概览
下图展示了从 API 请求到数据库写入的完整验证链路,包括 Pydantic 验证、业务规则检查与数据库约束验证。
sequenceDiagram
participant Client as "客户端"
participant API as "API 路由"
participant Pyd as "Pydantic 模式"
participant Svc as "服务层"
participant DB as "SQLAlchemy 模型"
participant SQL as "数据库"
Client->>API : "POST /staff"
API->>Pyd : "StaffCreate 验证"
Pyd-->>API : "验证通过/错误"
API->>Svc : "调用业务逻辑"
Svc->>DB : "构造模型实例"
DB->>SQL : "执行插入/更新"
SQL-->>DB : "约束检查结果"
DB-->>Svc : "返回持久化结果"
Svc-->>API : "返回业务结果"
API-->>Client : "统一响应"
图表来源
- backend/app/api/v1/staff.py
- backend/app/schemas/schemas.py
- backend/app/services/staff_service.py
- backend/app/models/models.py
详细组件分析
Pydantic 模型验证
- 字段类型与长度验证:通过 Field 的类型注解与 max_length/min_length 限制字符串长度;例如员工工号、姓名、职位、电话、邮箱等字段均设置了长度限制。
- 数值范围验证:通过 ge(大于等于)、le(小于等于)、gt(大于)等参数限制数值范围;例如基本工资、绩效系数、权重、最高分值、年份、月份等。
- 枚举验证:通过 str + Enum 的组合确保取值域的正确性;例如科室类型、员工状态、指标类型、考核状态等。
- 正则表达式验证:通过 pattern 参数对字符串格式进行约束;例如用户角色字段使用正则限制合法取值。
- 响应模式转换:通过 model_config(from_attributes=True) 将 ORM 对象直接转换为 Pydantic 模式,避免重复映射。
classDiagram
class StaffBase {
+employee_id : str
+name : str
+department_id : int
+position : str
+title : Optional[str]
+phone : Optional[str]
+email : Optional[str]
+base_salary : float
+performance_ratio : float
}
class StaffCreate {
+status : StaffStatus
+hire_date : Optional[datetime]
}
class StaffResponse {
+id : int
+status : StaffStatus
+hire_date : Optional[datetime]
+created_at : datetime
+updated_at : datetime
+department_name : Optional[str]
}
StaffCreate --|> StaffBase
StaffResponse --|> StaffBase
图表来源
章节来源
SQLAlchemy 约束验证
- 列类型与默认值:通过 String、Integer、Numeric、Boolean、DateTime、Enum 等类型定义字段属性与默认值;例如 Numeric(10,2) 用于金额与分数的精确存储。
- 索引优化:为常用查询字段添加索引,提升查询性能;例如科室类型、状态、年月组合等。
- CheckConstraint:通过 CheckConstraint 在数据库层强制业务约束;例如指标权重必须大于 0,财务金额必须大于等于 0。
- 外键关系:通过 ForeignKey 建立实体间的参照关系,配合级联策略保证数据一致性。
erDiagram
STAFF {
int id PK
string employee_id UK
string name
int department_id FK
string position
string title
string phone
string email
numeric base_salary
numeric performance_ratio
enum status
date hire_date
}
DEPARTMENTS {
int id PK
string name
string code UK
enum dept_type
int parent_id FK
int level
int sort_order
boolean is_active
}
INDICATORS {
int id PK
string name
string code UK
enum indicator_type
enum bs_dimension
numeric weight
numeric max_score
numeric target_value
string target_unit
text calculation_method
text assessment_method
text deduction_standard
text data_source
string applicable_dept_types
boolean is_veto
boolean is_active
}
ASSESSMENTS {
int id PK
int staff_id FK
int period_year
int period_month
string period_type
numeric total_score
numeric weighted_score
enum status
int assessor_id FK
int reviewer_id FK
datetime submit_time
datetime review_time
text remark
}
ASSESSMENT_DETAILS {
int id PK
int assessment_id FK
int indicator_id FK
numeric actual_value
numeric score
text evidence
text remark
}
SALARY_RECORDS {
int id PK
int staff_id FK
int period_year
int period_month
numeric base_salary
numeric performance_score
numeric performance_bonus
numeric deduction
numeric allowance
numeric total_salary
string status
text remark
}
DEPARTMENTS ||--o{ STAFF : "拥有"
STAFF ||--o{ ASSESSMENTS : "被考核"
ASSESSMENTS ||--o{ ASSESSMENT_DETAILS : "包含"
INDICATORS ||--o{ ASSESSMENT_DETAILS : "被评分"
图表来源
- backend/app/models/models.py
- backend/app/models/models.py
- backend/app/models/models.py
- backend/app/models/models.py
- backend/app/models/models.py
- backend/app/models/finance.py
章节来源
业务逻辑验证
- API 层业务规则:在创建与更新接口中,先进行 Pydantic 验证,再进行业务规则检查;例如创建员工前检查工号唯一性,创建指标前检查编码唯一性。
- 服务层业务规则:在服务层进行更复杂的业务一致性检查;例如更新考核记录时,仅允许在草稿或已驳回状态下进行修改,并重新计算总分与加权分。
- 统一错误处理:通过 HTTPException 抛出业务错误,结合全局异常处理器记录日志并返回统一的错误响应。
flowchart TD
Start(["开始"]) --> ValidatePyd["Pydantic 验证"]
ValidatePyd --> PydanticOK{"验证通过?"}
PydanticOK --> |否| ReturnError["返回验证错误"]
PydanticOK --> |是| BusinessCheck["业务规则检查"]
BusinessCheck --> BusinessOK{"业务规则通过?"}
BusinessOK --> |否| RaiseHTTP["抛出 HTTP 异常"]
BusinessOK --> |是| Persist["持久化到数据库"]
Persist --> Done(["结束"])
ReturnError --> Done
RaiseHTTP --> Done
图表来源
- backend/app/api/v1/staff.py
- backend/app/api/v1/indicators.py
- backend/app/services/assessment_service.py
- backend/app/main.py
章节来源
- backend/app/api/v1/staff.py
- backend/app/api/v1/indicators.py
- backend/app/services/assessment_service.py
- backend/app/main.py
验证错误处理与用户友好信息
- HTTP 异常:在业务规则不满足时,使用 HTTPException 返回明确的状态码与错误信息,如“员工不存在”、“工号已存在”、“指标不存在”等。
- 统一响应结构:API 返回统一的响应结构,包含状态码、消息、数据、分页信息等,便于前端展示与调试。
- 全局异常处理:注册 RequestValidationError 与 StarletteHTTPException 的处理器,记录错误日志并向上抛出,确保错误信息一致且可追踪。
章节来源
- backend/app/api/v1/staff.py
- backend/app/api/v1/indicators.py
- backend/app/api/v1/assessments.py
- backend/app/main.py
验证规则扩展与自定义验证器
- 扩展 Pydantic 验证:可在现有 Field 参数基础上增加更多约束,如自定义正则表达式、长度范围、数值边界等;对于复杂字段(如 JSON),可使用 Json 类型与自定义解析器。
- 自定义验证器:可通过 Pydantic 的 field_validator 或 root_validator 实现跨字段验证与复杂业务规则;例如在创建考核时,验证明细中的指标权重与总分计算的一致性。
- 数据库约束增强:在模型层新增 CheckConstraint 或复合索引,以强化数据完整性;例如为“员工工号+部门”的唯一性约束添加复合索引。
- 业务规则扩展:在服务层增加新的业务规则检查点,如在创建考核时检查指标是否适用于当前科室类型、是否启用等。
章节来源
- backend/app/schemas/schemas.py
- backend/app/models/models.py
- backend/app/services/assessment_service.py
依赖关系分析
- 版本要求:项目使用 FastAPI、SQLAlchemy、Pydantic 等核心依赖,版本在 requirements.txt 中声明,确保验证与 ORM 功能的稳定性。
- 模块间耦合:API 层依赖 Pydantic 模式与服务层;服务层依赖 SQLAlchemy 模型;模型层依赖数据库驱动与 Alembic 迁移工具。
- 异常处理:全局异常处理器统一处理验证与业务异常,减少重复代码并提升用户体验。
graph LR
Req["requirements.txt"] --> FastAPI["FastAPI"]
Req --> SQLAlchemy["SQLAlchemy"]
Req --> Pydantic["Pydantic"]
API["API 路由"] --> PydanticSchema["Pydantic 模式"]
API --> Service["服务层"]
Service --> Model["SQLAlchemy 模型"]
Model --> DB["数据库"]
Main["main.py"] --> API
Main --> Service
Main --> Model
图表来源
- backend/requirements.txt
- backend/app/api/v1/staff.py
- backend/app/services/staff_service.py
- backend/app/models/models.py
- backend/app/main.py
章节来源
性能考虑
- 索引优化:为高频查询字段(如科室类型、状态、年月组合)建立索引,降低查询成本。
- 数值精度:使用 Numeric 类型存储金额与分数,避免浮点误差;合理设置精度与小数位数。
- 查询优化:在服务层使用 selectinload 等策略预加载关联对象,减少 N+1 查询问题。
- 异步 I/O:利用 SQLAlchemy 异步引擎与 FastAPI 的异步特性,提升并发处理能力。
故障排除指南
- Pydantic 验证失败:检查请求体字段类型、长度与范围是否符合模式定义;查看响应中的错误字段与原因。
- 业务规则失败:确认业务状态是否允许当前操作(如仅草稿或已驳回状态可更新);检查唯一性约束冲突(如工号、指标编码)。
- 数据库约束失败:检查 CheckConstraint 与索引是否满足;确认外键关系是否正确。
- 异常处理:查看全局异常处理器的日志输出,定位具体错误位置与堆栈信息。
章节来源
结论
本系统通过“Pydantic 模式验证 + SQLAlchemy 数据库约束 + 服务层业务规则”的三层验证机制,确保了数据在进入业务流程前后的完整性与一致性。API 层负责输入验证与业务规则检查,服务层负责复杂业务逻辑与数据一致性,模型层负责数据结构与约束定义。配合统一的异常处理与日志记录,系统在保证功能正确的同时,也具备良好的可维护性与可扩展性。未来可在 Pydantic 中引入自定义验证器与复杂字段解析,在模型层增加更多数据库约束,并在服务层扩展业务规则检查点,进一步完善验证体系。