django.forms
包提供了 HTML 表单验证的功能,在没有使用 DRF 的情况下,无法合理地处理 API 传参的验证,其中传参验证中就缺少了参数默认值的设置。
层次结构
django.forms
包提供的 Field
类如下:
__all__ = (
'Field', 'CharField', 'IntegerField',
'DateField', 'TimeField', 'DateTimeField', 'DurationField',
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
'SplitDateTimeField', 'GenericIPAddressField', 'FilePathField',
'JSONField', 'SlugField', 'TypedChoiceField', 'TypedMultipleChoiceField',
'UUIDField',
)
继承关系如下图:
Field: 字段基类
- InlineForeignKeyField: 关联模型的主键字段
- CharField: 字符串字段
- RegexField: 正则字符串字段
- UrlField: URL 字段
- SlugField: 是否允许 unicode 字符串
- GenericIPAdressField: IP 字段
- EmailField: 邮箱字段
- UUIDField: UUID 字段
- JSONField: JSON 字符串
- IntegerField: 整数字段
- FloatField: 浮点数字段
- DecimalField: 十进制小数字段
- BaseTemporalField: 表示时间
- DatelField: 日期字段
- TimeField: 时间字段
- DateTimeField: (日期、时间)字段
- DurationField: 时间段字段
- FileField: 文件字段
- ImageField: 图片字段
- BooleanField: 布尔字段
- NullBooleanField: 布尔字段(可为 null)
- ChoiceField: 可选项字段
- ModelChoiceField: 模型选项字段(QuerySet)
- ModelMultipleChoiceField: 模型选项字段(QuerySet,可多个)
- TypedChoiceField: 可选项字段(强制类型)
- MultipleChoiceField: 可选项字段(多选)
- TypedMultipleChoiceField: 可选项字段(多选,强制类型)
- FilePathField: 文件路径字段
- ComboField: 组合字段,同时使用多个字段验证器
- MultiValueField: 聚合多个字段的逻辑
- SplitDateTimeField: 多个时间值字段
基类 Field
的构造函数的声明如下:
def __init__(self, *, required=True, widget=None, label=None, initial=None,
help_text='', error_messages=None, show_hidden_initial=False,
validators=(), localize=False, disabled=False, label_suffix=None):
initial 参数
其中有一个 initial
参数,可以用来表示 Form
渲染出的 HTML 代码中的显示值,但并不会给字段赋值,如:
from django.http import HttpRequest, JsonResponse
from django import forms
class ExampleForm(forms.Form):
name = forms.CharField(required=False, initial='a2htray')
def django_forms_field_initial(request: HttpRequest):
form = ExampleForm(request.GET)
if form.is_valid():
data = form.cleaned_data
print('data', data)
print(form)
else:
print(form.errors)
return JsonResponse({})
return JsonResponse({})
请求该接口打印的信息如下:
data {'name': ''}
<tr><th><label for="id_name">Name:</label></th><td><input type="text" name="name" id="id_name"></td></tr>
可见,django 提供的 Field
类没有提供类似于默认值的功能。比如,当用户不能给出默认的 name
值时进行赋值。
自定义 default 参数
封装一个需要提供默认值功能的字段类,这里以 TypedChoiceField
为例,其中 TypedChoiceField._coerce
方法本身也提供了一定的验证功能,看源码:
class TypedChoiceField(ChoiceField):
# ...
def _coerce(self, value):
if value == self.empty_value or value in self.empty_values:
return self.empty_value # 需要的修改地方
try:
value = self.coerce(value)
except (ValueError, TypeError, ValidationError):
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
params={'value': value},
)
return value
def clean(self, value):
value = super().clean(value)
return self._coerce(value)
当传值解析为指定的 empty_value
或在 empty_values
中时,返回指定的默认值,其余不变。
class MyTypeChoiceField(forms.TypedChoiceField):
def __init__(self, *, default=None, **kwargs):
self.default = default
super().__init__(**kwargs)
def _coerce(self, value):
if value == self.empty_value or value in self.empty_values:
return self.default
else:
try:
value = self.coerce(value)
except (ValueError, TypeError, ValidationError):
raise ValidationError(
self.error_messages['invalid_choice'],
code='invalid_choice',
params={'value': value},
)
return value
那么在使用 MyTypedChoiceField
时可以指定 default
参数,如:
GENDER_CHOICES = (
(0, 'Male'),
(1, 'Female'),
)
class Payload(forms.Form):
gender = MyTypeChoiceField(coerce=lambda p: int(p), choices=GENDER_CHOICES, required=False, default=0)
def get_payload_validate(request: HttpRequest):
payload = Payload(request.GET)
if not payload.is_valid():
return JsonResponse({
'errors': payload.errors,
})
payload = payload.cleaned_data
return JsonResponse(payload)
不带任何参数值请求该接口时的返回如下:
{
"gender": 0
}
不同的 Field
子类也可进行类似的继承再修改。
评论