签入版本
This commit is contained in:
@@ -0,0 +1,226 @@
|
||||
# Form层规范
|
||||
|
||||
## 概述
|
||||
|
||||
Form 层负责数据验证,使用 Django `ModelForm` 实现。每个模块的 `forms.py` 定义表单验证类,包含字段验证规则和中文错误提示。
|
||||
|
||||
:::tip 设计原则
|
||||
- 继承 `forms.ModelForm`
|
||||
- 每个字段定义中文 `error_messages`
|
||||
- 使用 `Meta.fields` 指定验证字段
|
||||
- 验证在 Service 层 ORM 操作之前执行
|
||||
:::
|
||||
|
||||
## 完整示例
|
||||
|
||||
以案例模块为例,`application/example/forms.py`:
|
||||
|
||||
```python
|
||||
from django import forms
|
||||
from application.example import models
|
||||
|
||||
|
||||
class ExampleForm(forms.ModelForm):
|
||||
"""案例表单验证类"""
|
||||
|
||||
# 案例名称
|
||||
name = forms.CharField(
|
||||
required=True,
|
||||
max_length=100,
|
||||
error_messages={
|
||||
'required': '案例名称不能为空',
|
||||
'max_length': '案例名称长度不得超过100个字符',
|
||||
}
|
||||
)
|
||||
|
||||
# 案例图片
|
||||
avatar = forms.CharField(
|
||||
required=False,
|
||||
max_length=255,
|
||||
error_messages={
|
||||
'max_length': '案例图片长度不得超过255个字符',
|
||||
}
|
||||
)
|
||||
|
||||
# 案例类型
|
||||
type = forms.IntegerField(
|
||||
required=True,
|
||||
min_value=1,
|
||||
max_value=4,
|
||||
error_messages={
|
||||
'required': '案例类型不能为空',
|
||||
'min_value': '案例类型值不能小于1',
|
||||
'max_value': '案例类型值不能大于4',
|
||||
}
|
||||
)
|
||||
|
||||
# 案例状态
|
||||
status = forms.IntegerField(
|
||||
required=True,
|
||||
min_value=1,
|
||||
max_value=2,
|
||||
error_messages={
|
||||
'required': '案例状态不能为空',
|
||||
'min_value': '案例状态值不能小于1',
|
||||
'max_value': '案例状态值不能大于2',
|
||||
}
|
||||
)
|
||||
|
||||
# 排序
|
||||
sort = forms.IntegerField(
|
||||
required=True,
|
||||
error_messages={
|
||||
'required': '排序不能为空',
|
||||
}
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = models.Example
|
||||
fields = ['name', 'avatar', 'type', 'status', 'sort']
|
||||
```
|
||||
|
||||
## 字段类型
|
||||
|
||||
| Django 表单字段 | 说明 | 常用参数 |
|
||||
|:----|:----|:----|
|
||||
| `CharField` | 字符串 | `max_length`, `min_length` |
|
||||
| `IntegerField` | 整数 | `min_value`, `max_value` |
|
||||
| `FloatField` | 浮点数 | `min_value`, `max_value` |
|
||||
| `DecimalField` | 精确小数 | `max_digits`, `decimal_places` |
|
||||
| `BooleanField` | 布尔值 | - |
|
||||
| `DateTimeField` | 日期时间 | `input_formats` |
|
||||
| `DateField` | 日期 | `input_formats` |
|
||||
| `EmailField` | 邮箱 | `max_length` |
|
||||
| `URLField` | URL | `max_length` |
|
||||
|
||||
## 错误消息规范
|
||||
|
||||
每个字段必须定义中文 `error_messages`:
|
||||
|
||||
```python
|
||||
name = forms.CharField(
|
||||
required=True,
|
||||
max_length=100,
|
||||
error_messages={
|
||||
'required': '案例名称不能为空', # 必填验证
|
||||
'max_length': '案例名称长度不得超过100个字符', # 长度验证
|
||||
'min_length': '案例名称长度不能少于2个字符', # 最小长度
|
||||
}
|
||||
)
|
||||
|
||||
type = forms.IntegerField(
|
||||
required=True,
|
||||
min_value=1,
|
||||
max_value=4,
|
||||
error_messages={
|
||||
'required': '案例类型不能为空', # 必填验证
|
||||
'min_value': '案例类型值不能小于1', # 最小值验证
|
||||
'max_value': '案例类型值不能大于4', # 最大值验证
|
||||
'invalid': '案例类型格式不正确', # 格式验证
|
||||
}
|
||||
)
|
||||
```
|
||||
|
||||
### 常用错误消息键
|
||||
|
||||
| 键 | 说明 | 适用字段 |
|
||||
|:----|:----|:----|
|
||||
| `required` | 必填验证 | 所有字段 |
|
||||
| `max_length` | 最大长度 | CharField |
|
||||
| `min_length` | 最小长度 | CharField |
|
||||
| `max_value` | 最大值 | IntegerField/FloatField |
|
||||
| `min_value` | 最小值 | IntegerField/FloatField |
|
||||
| `invalid` | 格式验证 | 所有字段 |
|
||||
| `unique` | 唯一性验证 | 需手动实现 |
|
||||
|
||||
## Meta 类配置
|
||||
|
||||
```python
|
||||
class Meta:
|
||||
# 绑定模型
|
||||
model = models.Example
|
||||
|
||||
# 指定验证字段(只验证以下字段)
|
||||
fields = ['name', 'avatar', 'type', 'status', 'sort']
|
||||
|
||||
# 排除字段(不验证以下字段)
|
||||
# exclude = ['create_user', 'update_user']
|
||||
```
|
||||
|
||||
:::tip fields vs exclude
|
||||
- `fields`:白名单,只验证列出的字段
|
||||
- `exclude`:黑名单,排除列出的字段
|
||||
- 推荐使用 `fields`,更明确
|
||||
:::
|
||||
|
||||
## 在 Service 中使用
|
||||
|
||||
```python
|
||||
from application.example import forms
|
||||
from utils import R, regular
|
||||
|
||||
def add_example(request):
|
||||
"""添加案例"""
|
||||
# 解析请求参数
|
||||
data, error = parse_request_body(request)
|
||||
if error:
|
||||
return R.failed(msg=error)
|
||||
|
||||
# 表单验证
|
||||
form = forms.ExampleForm(data)
|
||||
if not form.is_valid():
|
||||
return R.failed(msg=regular.get_err(form))
|
||||
|
||||
try:
|
||||
cleaned_data = form.cleaned_data
|
||||
# 使用 cleaned_data 创建记录
|
||||
Example.objects.create(
|
||||
name=cleaned_data.get('name'),
|
||||
type=cleaned_data.get('type'),
|
||||
status=cleaned_data.get('status'),
|
||||
sort=cleaned_data.get('sort'),
|
||||
)
|
||||
return R.ok(msg="创建成功")
|
||||
except Exception as e:
|
||||
return R.failed(msg="添加失败")
|
||||
```
|
||||
|
||||
## 错误信息提取
|
||||
|
||||
使用 `regular.get_err(form)` 提取表单验证错误信息:
|
||||
|
||||
```python
|
||||
from utils import regular
|
||||
|
||||
form = forms.ExampleForm(data)
|
||||
if not form.is_valid():
|
||||
error_msg = regular.get_err(form) # 返回第一个错误的中文提示
|
||||
return R.failed(msg=error_msg)
|
||||
```
|
||||
|
||||
## 自定义验证方法
|
||||
|
||||
```python
|
||||
class ExampleForm(forms.ModelForm):
|
||||
name = forms.CharField(required=True, max_length=100)
|
||||
|
||||
def clean_name(self):
|
||||
"""自定义验证:检查名称是否包含敏感词"""
|
||||
name = self.cleaned_data.get('name')
|
||||
if '敏感词' in name:
|
||||
raise forms.ValidationError('名称包含敏感词')
|
||||
return name
|
||||
|
||||
def clean(self):
|
||||
"""全局验证:检查字段间的关系"""
|
||||
cleaned_data = super().clean()
|
||||
start_date = cleaned_data.get('start_date')
|
||||
end_date = cleaned_data.get('end_date')
|
||||
if start_date and end_date and start_date > end_date:
|
||||
raise forms.ValidationError('开始日期不能晚于结束日期')
|
||||
return cleaned_data
|
||||
```
|
||||
|
||||
## 总结
|
||||
|
||||
Form 层使用 Django `ModelForm` 实现数据验证,每个字段定义中文 `error_messages`。在 Service 层 ORM 操作之前执行验证,使用 `regular.get_err(form)` 提取错误信息。支持自定义验证方法(`clean_{field}`)和全局验证(`clean`)。
|
||||
Reference in New Issue
Block a user