签入版本
This commit is contained in:
@@ -0,0 +1,125 @@
|
||||
# Pydantic Schema
|
||||
|
||||
Schema 层负责请求数据的校验。项目使用 Pydantic v2 的 `BaseModel` 定义表单类,通过 `Field` 约束字段格式,Tornado 在接收请求体时自动执行校验。
|
||||
|
||||
## 文件位置
|
||||
|
||||
```
|
||||
src/modules/position/schemas.py
|
||||
```
|
||||
|
||||
## 完整代码
|
||||
|
||||
```python
|
||||
from typing import Optional
|
||||
|
||||
from pydantic import BaseModel, Field
|
||||
from core.base_schema import BaseSchema
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 岗位表单类
|
||||
# ============================================================
|
||||
class PositionForm(BaseSchema):
|
||||
"""岗位创建/编辑表单"""
|
||||
name: str = Field(..., min_length=1, max_length=150, description="岗位名称")
|
||||
status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")
|
||||
sort: int = Field(..., ge=0, le=99999, description="岗位排序")
|
||||
|
||||
|
||||
# ============================================================
|
||||
# 设置状态表单类
|
||||
# ============================================================
|
||||
class PositionStatusForm(BaseModel):
|
||||
"""岗位状态更新表单"""
|
||||
id: int = Field(..., gt=0, description="岗位ID")
|
||||
status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")
|
||||
```
|
||||
|
||||
## 代码解析
|
||||
|
||||
### 基类选择
|
||||
|
||||
| 基类 | 用途 | 包含字段 |
|
||||
|:----|:----|:----|
|
||||
| `BaseSchema` | 创建/编辑通用表单 | 自带可选 `id` 字段(`Optional[int]`),编辑时传入 |
|
||||
| `BaseModel` | 特定操作表单 | 无额外字段,按需定义 |
|
||||
|
||||
创建和编辑共用 `PositionForm`:创建时不传 `id`,编辑时传入 `id`。`BaseSchema` 的 `id` 字段定义为 `Optional[int] = Field(None, gt=0)`,创建时可省略。
|
||||
|
||||
### Field 约束
|
||||
|
||||
```python
|
||||
name: str = Field(..., min_length=1, max_length=150, description="岗位名称")
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
|:----|:----|
|
||||
| `...` | 必填(Ellipsis) |
|
||||
| `min_length=1` | 最小长度 1,不允许空字符串 |
|
||||
| `max_length=150` | 最大长度 150 |
|
||||
| `description` | Swagger 文档中的字段说明 |
|
||||
|
||||
```python
|
||||
status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")
|
||||
```
|
||||
|
||||
| 参数 | 含义 |
|
||||
|:----|:----|
|
||||
| `ge=1` | 大于等于(Greater Equal) |
|
||||
| `le=2` | 小于等于(Less Equal) |
|
||||
|
||||
```python
|
||||
sort: int = Field(..., ge=0, le=99999, description="岗位排序")
|
||||
```
|
||||
|
||||
排序字段允许 0 到 99999 的范围。
|
||||
|
||||
### 状态更新单独建类
|
||||
|
||||
```python
|
||||
# ============================================================
|
||||
# 设置状态表单类
|
||||
# ============================================================
|
||||
class PositionStatusForm(BaseModel):
|
||||
"""岗位状态更新表单"""
|
||||
id: int = Field(..., gt=0, description="岗位ID")
|
||||
status: int = Field(..., ge=1, le=2, description="岗位状态:1-在用 2-停用")
|
||||
```
|
||||
|
||||
状态更新接口只需要 `id` 和 `status` 两个字段,与创建/编辑表单分开定义,接口语义更清晰。
|
||||
|
||||
## 如何在 Service 中使用
|
||||
|
||||
Schema 在 Service 层通过 `create_schema` / `update_schema` / `status_schema` 声明,`BaseService` 的 `add()` / `update()` / `update_status()` 方法自动执行校验:
|
||||
|
||||
```python
|
||||
class PositionService(BaseService):
|
||||
model = Position
|
||||
repo_cls = PositionRepository
|
||||
create_schema = PositionSchema # 新增/编辑时校验
|
||||
update_schema = PositionSchema # 编辑时校验
|
||||
status_schema = PositionStatusSchema # 状态变更时校验
|
||||
```
|
||||
|
||||
校验由 `BaseService.validate()` 方法内部调用 `schema_cls.model_validate(data)` 完成。校验失败时抛出 `ValidationError`,由 `BaseHandler.write_error` 统一转换为标准错误响应:
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 1,
|
||||
"data": null,
|
||||
"msg": "name: String should have at least 1 character",
|
||||
"ok": false
|
||||
}
|
||||
```
|
||||
|
||||
## 开发要点
|
||||
|
||||
1. **创建/编辑共用一个表单类**:继承 `BaseSchema`,利用其内置的可选 `id` 字段
|
||||
2. **特殊操作单独建类**:如状态更新、排序调整等,只包含必要的字段
|
||||
3. **合理设置约束**:`min_length` / `max_length` / `ge` / `le` / `gt` 等,让框架自动校验
|
||||
4. **description 建议填写**:用于字段说明,方便团队理解字段含义
|
||||
|
||||
## 总结
|
||||
|
||||
Pydantic Schema 通过 `BaseSchema` 继承公共字段(id),使用 `Field(...)` 声明约束。在 Service 层通过 `create_schema` / `update_schema` / `status_schema` 声明,`BaseService` 自动执行校验。特殊操作单独建类。
|
||||
Reference in New Issue
Block a user