django的Form组件主要实现的功能:
1、渲染html代码(不用手写相关前端表单代码)
2、校验数据
3、展示提示信息
Form组件的定义
以注册功能为例
from django import forms
class RegForm(forms.Form):
user = forms.CharField()
pwd = forms.CharField()
一个功能的form组件是一个类,这个类必须继承forms中的Form类(和模型类定义的形式有点类似);
这个类内部定义的成员变量就对应着前端页面的一个个input标签。
Form组件的基本使用
1、在视图函数中
def reg(request):
form_obj = RegForm()
return render(request, 'reg.html', {'form_obj': form_obj})
只需要将Form类实例化,传给对应的前端页面完成渲染,即可展示相应的表单内容
2、在模板文件中渲染
由于form组件只提供表单内部的元素,不包含表单以及按钮。所以在模板文件中需要手写相关代码。
<form action="" method="post">
{% csrf_token %}
{{ form_obj.as_p }}
<button>注册</button>
</form>
以上代码在前端显示为
form_obj.as_p:将每个元素以p标签形式渲染出来(p标签内部有label和input)
3、标签渲染的方式
a、以不同形式,自动将所有元素一次性渲染出来,不利于后续扩展。
{{ form_obj.as_p }}
{{ form_obj.as_ul }}
{{ form_obj.as_table }}
b、根据from_obj内部的成员变量,手动生成想要的元素以及展示形式,扩展性高,代码冗余。
<p>{{ form_obj.user.label }}:{{ form_obj.user }}</p>
<p>{{ form_obj.pwd.label }}:{{ form_obj.pwd }}</p>
c、利用for循环生成元素,扩展性高,代码精简。
{% for form in form_obj %}
<p>{{ form.label }}:{{ form }}</p>
{% endfor %}
4、校验数据
后端要想使用Form组件进行数据的校验,首先需要关闭前端的校验(直接将数据给后端)
只需要在from标签内加上novalidate属性即可
后端校验数据:
def reg(request):
form_obj = RegForm() # 空的Form对象
if request.method == 'POST':
form_obj = RegForm(request.POST) # 包含用户提交的数据的From对象
if form_obj.is_valid(): # 对数据进行校验
return HttpResponse('ok')
# 如果校验不成功,那么render返回的form_obj中就包含了对应字段的错误信息,可以渲染在前端
return render(request, 'reg.html', {'form_obj': form_obj})
前端可以通过{{ form_obj.errors }}打印出所有的错误,也可以根据不同字段来打印错误信息{{ form_obj.user.errors }}
如果某个字段有多个错误还可以通过下标的方式选择打印错误信息{{ form_obj.user.errors.0 }},否则是以列表的形式展示数据
form组件会在数据不合法的情况下,保存上次的数据,让用户基于上次的数据进行修改。
Form常用的字段和参数
1、常用字段
Form组件可用的字段有:
__all__ = (
'Field', 'CharField', 'IntegerField',
'DateField', 'TimeField', 'DateTimeField', 'DurationField',
'RegexField', 'EmailField', 'FileField', 'ImageField', 'URLField',
'BooleanField', 'NullBooleanField', 'ChoiceField', 'MultipleChoiceField',
'ComboField', 'MultiValueField', 'FloatField', 'DecimalField',
'SplitDateTimeField', 'GenericIPAddressField', 'FilePathField',
'SlugField', 'TypedChoiceField', 'TypedMultipleChoiceField', 'UUIDField',
)
CharField——文本输入框
EmailField——邮箱文本输入框(输入的字段必须符合邮箱的格式)
ChoiceField——单选框 默认是select
MultipleChoiceField——多选框 默认是select
2、字段参数
initial——设置默认值
error_messages——重写错误信息(默认错误信息是固定格式且是英文的)
error_messages={
"required": "不能为空",
"invalid": "格式错误",
"min_length": "用户名最短8位"
}
也可以不设置error_messages,直接将settings里的LANGUAGE_CODE设置成'zh-hans',这样所有错误信息都可以中文显示
label——设置字段名,前端默认展示的字段名是首字母大写的成员变量名
choices——设置选择框的选项,每个选项都以元组形式存储(存储在数据库的值,前端页面展示的值)
required——设置字段是必填项
disabled——设置input是否禁用
validators——设置字段的校验器,对应值是一个列表,列表内存放函数对象,即相关校验函数。
widget——插件,修改input的类型
widget=forms.PasswordInput(attrs={'class':'form-control c1 c2'})
修改input类型的同时还能够设置属性值
可选的类型如下:
__all__ = (
'Media', 'MediaDefiningClass', 'Widget', 'TextInput', 'NumberInput',
'EmailInput', 'URLInput', 'PasswordInput', 'HiddenInput',
'MultipleHiddenInput', 'FileInput', 'ClearableFileInput', 'Textarea',
'DateInput', 'DateTimeInput', 'TimeInput', 'CheckboxInput', 'Select',
'NullBooleanSelect', 'SelectMultiple', 'RadioSelect',
'CheckboxSelectMultiple', 'MultiWidget', 'SplitDateTimeWidget',
'SplitHiddenDateTimeWidget', 'SelectDateWidget',
)
通过修改CharField的类型,可以实现其他字段的效果。
补充:
前端展示选择框数据的时候,往往这些数据都是写死的。
可以将选择框数据单独存放在表中,然后将该表的查询结果作为展示数据,这样前端展示选择框数据时就可以实现动态展示。
首先需要导入 from django.forms import models as form_model
hobby = form_model.ModelMultipleChoiceField( queryset=models.Hobby.objects.all(), widgets=forms.CheckboxSelectMultiple)
校验方法
1、设置校验器
定义校验函数
from django.core.exceptions import ValidationError
def check_name(value):
if '1' in value:
raise ValidationError('该用户名不符合要求')
在相应字段加上validators参数
user = forms.CharField(label='用户名', validators=[check_name])
校验函数内,出现不符合校验标准的情况必须抛出ValidationError异常,异常信息作为校验错误的提示信息
2、定义钩子函数
钩子函数需要定义在Form类当中
a、局部钩子
函数的命名为clean_字段名
class RegForm(forms.Form):
user = forms.CharField(label='用户名')
pwd = forms.CharField(label='密码', widget=forms.PasswordInput())
def clean_user(self):
value = self.cleaned_data.get('user')
if '1' in value: # 不符合校验规则
raise ValidationError('该用户名不符合要求')
# 符合校验规则
return value
cleaned_data是经过is_valid()校验过,没有问题的数据字典
使用is_valid()方法前,没有cleaned_data字典,获取时会报错
只有在is_valid()方法之后,才生成了cleaned_data字典
b、全局钩子
全局钩子命名为clean,针对所有字段
def clean(self):
username = self.cleaned_data.get('user')
pwd = self.cleaned_data.get('pwd')
if '1' in username: # 不符合校验规则
raise ValidationError('该用户名不符合要求')
if '1' in pwd:
raise ValidationError('密码包含禁用词')
# 符合校验规则 返回所有字段的值
return self.cleaned_data
此时,抛出的错误信息存放在全局{{ form_obj.errors }},不能通过字段名的错误信息获取到
要想将错误信息存放在某个字段当中,可以通过以下方法:
self.add_error(字段名,错误信息)
self.add_error('pwd', '错误')
注意:
钩子函数中出现不符合校验规则的情况,必须要抛出异常。
即便已经将某个错误信息存放到指定字段中,也需要抛出异常(固定搭配)
ModelForm
ModelForm就是model和form的结合。
原本在定义form类的时候,需要自己表单中的字段元素。
有时候可以根据model类中定义好的字段来生成相应表单,如用户信息(账号密码)。
1、定义
class RegForm(forms.ModelForm):
class Meta:
model = User
fields = '__all__'
widgets = {
'username': forms.TextInput(attrs={'class': 'lowin-input'}),
'pwd': forms.PasswordInput(attrs={'class': 'lowin-input'}),
}
error_messages = {
'username': {
'required': '用户名不能为空',
'unique': '用户名已存在,请重新输入',
},
'pwd': {
'required': '密码不能为空',
},
}
class Meta中的参数说明:
model = models.User # 对应的Model中的类 fields = "__all__" # 字段,如果是__all__,说明model类中的所有字段都将被用于生成表单 exclude = None # 排除的字段,排除掉的字段,不会生成在表单中 labels = None # 提示信息 help_texts = None # 帮助提示信息 widgets = None # 自定义插件 error_messages = None # 自定义错误信息
2、使用方式和Form基本一致
ModelForm对象有一个save方法,可以直接将接收到的有效数据保存到数据库中。
前提的是:
该ModelForm对象不是空对象,必须用接收到的数据初始化
form_obj = RegForm(request.POST)
if form_obj.is_valid():
form_obj.save()
return HttpResponse('ok')
3、调整form中字段显示的先后顺序
在class Meta中,将fields的值改成列表,列表中字段的先后顺序,就是前端for循环的迭代的先后顺序
如:
fields = ['username', 'password', 're_password', 'mobile_phone', 'code']