form组件
form组件实现功能:
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验,提供错误提示
- 保留上次输入内容
定义form组件
from django import forms
class RegForm(forms.Form):
username = forms.CharField(
label='用户名',
min_length=6,
initial='张三',#初始值
required=True,#必填
validators=[],#填写校验器
error_messages={#错误信息
'required': '用户名是必填项',
'min_length': '用户名长度不能小于6位'
}
)
#widget生成什么样式的输入框
pwd = forms.CharField(label='密码', widget=forms.PasswordInput)
gender = forms.ChoiceField(
choices=((1, '男'), (2, '女')),
widget=forms.RadioSelect
)
hobby = forms.ModelMultipleChoiceField(
queryset=models.Hobby.objects.all(),
)# 数据库变更实时更新
views函数使用form
def reg(request):
form_obj = RegForm() #实例化一个对象,然后传到模板生成输入框
if request.method == 'POST':
form_obj = RegForm(request.POST) #新建一个带数据的对象覆盖空的
if form_obj.is_valid(): # 对数据进行校验,然后就有了error信息
# 在数据库插入数据
print(form_obj.cleaned_data) # 通过校验的数据
return HttpResponse('注册成功')
return render(request, 'reg.html', {'form_obj': form_obj})
模板使用form
<form action="" method="post" novalidate> <!-- novalidate取消前端校验 -->
{% csrf_token %}
<p>
<label for="{{ form_obj.username.id_for_label }}">
{{ form_obj.username.label }}
</label>
{{ form_obj.username }}
{{ form_obj.username.errors.0 }}
</p>
<p>
<label for="{{ form_obj.pwd.id_for_label }}">
{{ form_obj.pwd.label }}
</label>
{{ form_obj.pwd }}
{{ form_obj.pwd.errors.0 }}
</p>
<p>
<label for="{{ form_obj.re_pwd.id_for_label }}">
{{ form_obj.re_pwd.label }}
</label>
{{ form_obj.re_pwd }}
{{ form_obj.re_pwd.errors.0 }}
</p>
form对象前端应用
{{ form_obj.as_p }} ——》 生成一个个P标签 包含着 input label
{{ form_obj.errors }} ——》 form表单中所有字段的错误ui-li格式
{{ form_obj.username }} ——》 一个字段对应的input框
{{ form_obj.username.label }} ——》 该字段的提示
{{ form_obj.username.id_for_label }} ——》 该字段input框的id
{{ form_obj.username.errors }} ——》 该字段的所有的错误
{{ form_obj.username.errors.0 }} ——》 该字段的第一个错误,字符串格式
常用字段
Field
required=True, 是否允许为空
widget=None, HTML插件
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
help_text='', 帮助信息(在标签旁边显示)
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
localize=False, 是否支持本地化
disabled=False, 是否可以编辑
label_suffix=None Label内容后缀
CharField(Field)
max_length=None, 最大长度
min_length=None, 最小长度
strip=True 是否移除用户输入空白
ChoiceField(Field)
...
choices=(), 选项,如:choices = ((0,'上海'),(1,'北京'),)
required=True, 是否必填
widget=None, 插件,默认select插件
label=None, Label内容
initial=None, 初始值
help_text='', 帮助提示
ModelChoiceField(ChoiceField)
... django.forms.models.ModelChoiceField
queryset, # 查询数据库中的数据
empty_label="---------", # 默认空显示内容
to_field_name=None, # HTML中value的值对应的字段
limit_choices_to=None # ModelForm中对queryset二次筛选
字段参数
required=True, 是否允许为空
widget=None, HTML插件
min_length=8
max_length=16
label=None, 用于生成Label标签或显示内容
initial=None, 初始值
error_messages=None, 错误信息 {'required': '不能为空', 'invalid': '格式错误'}
validators=[], 自定义验证规则
disabled=False, 是否可以编辑
常用插件
#CharField
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})
#ChoiceField
widget=forms.widgets.RadioSelect()#单radio值为字符串
widget=forms.widgets.Select() #单选Select
widget=forms.widgets.CheckboxInput()#单选checkbox
# MultipleChoiceField
widget=forms.widgets.CheckboxSelectMultiple()#多选checkbox
widget=forms.widgets.SelectMultiple #()多选Select
关于choice的注意事项:
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。
方式一:
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
hobby = forms.ChoiceField(
choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
widget=forms.widgets.SelectMultiple
# choices=models.Hobby.objects.values_list('id', 'name'),
#静态字段只加载一次
)
def __init__(self, *args, **kwargs):
super(RegForm, self).__init__(*args, **kwargs)
self.fields['hobby'].choices = models.Hobby.objects.values_list('id', 'name')
方式二:
from django import forms
from django.forms import fields
from django.forms import models as form_model
class MyForm(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.Hobby.objects.all()) # 多选
# authors = form_model.ModelChoiceField(queryset=models.Hobby.objects.all()) # 单选
校验
1.内置校验
required=True
min_length
max_length
。。。
2.自定义校验器
1.自定义校验函数
import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError
# 自定义验证规则
def mobile_validate(value):
mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
if not mobile_re.match(value):
raise ValidationError('手机号码格式错误')
class PublishForm(Form):
title = fields.CharField(max_length=20,
min_length=5,
error_messages={'required': '标题不能为空',
'min_length': '标题最少为5个字符',
'max_length': '标题最多为20个字符'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': '标题5-20个字符'}))
# 使用自定义验证规则
phone = fields.CharField(validators=[mobile_validate, ],
error_messages={'required': '手机不能为空'},
widget=widgets.TextInput(attrs={'class': "form-control",
'placeholder': u'手机号码'}))
email = fields.EmailField(required=False,
error_messages={'required': u'邮箱不能为空','invalid': u'邮箱格式错误'},
widget=widgets.TextInput(attrs={'class': "form-control", 'placeholder': u'邮箱'}))
2.使用内置的校验器
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
user = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
3.钩子函数:
-
局部钩子
def clean_username(self): # 局部钩子 # 通过校验规则 必须返回当前字段的值 # 不通过校验规则 抛出异常 v = self.cleaned_data.get('username') if 'sb' in v: raise ValidationError('敏感词汇') else: return v
-
全局钩子
def clean(self): # 全局钩子 # 通过校验规则 必须返回当前所有字段的值 # 不通过校验规则 抛出异常 '__all__' pwd = self.cleaned_data.get('pwd') re_pwd = self.cleaned_data.get('re_pwd') if pwd == re_pwd: return self.cleaned_data else: self.add_error('re_pwd','两次密码不一致!!!!!') raise ValidationError('两次密码不一致')
is_valid的流程:
1.执行full_clean()的方法:
定义错误字典
定义存放清洗数据的字典
2.执行_clean_fields方法:
循环所有的字段
获取当前的值
对进行校验 ( 内置校验规则 自定义校验器)
-
通过校验
self.cleaned_data[name] = value
如果有局部钩子,执行进行校验:
通过校验——》 self.cleaned_data[name] = value
不通过校验——》 self._errors 添加当前字段的错误 并且 self.cleaned_data中当前字段的值删除掉
-
没有通过校验
self._errors 添加当前字段的错误
3.执行全局钩子clean方法
ModelForm
orm与model的终极结合。
class BookForm(forms.ModelForm):
class Meta:
model = models.Book
fields = "__all__"
labels = {
"title": "书名",
"price": "价格"
}
widgets = {
"password": forms.widgets.PasswordInput(attrs={"class": "c1"}),
}
class Meta:下常用参数:
model = models.Student # 对应的Model中的类
fields = "__all__" # 字段,如果是__all__,就是表示列出所有的字段
exclude = None # 排除的字段
labels = None # 提示信息
help_texts = None # 帮助提示信息
widgets = None # 自定义插件
error_messages = None # 自定义错误信息
注册示例
from crm import models
from django import forms
from django.core.exceptions import ValidationError
import hashlib
class RegForm(forms.ModelForm):
#需对密码进行加密,重写ModelForm字段
password = forms.CharField(min_length=6,
widget=forms.PasswordInput(attrs={'placeholder': '您的密码', 'autocomplete': 'off'}))
re_password = forms.CharField(min_length=6,
widget=forms.PasswordInput(attrs={'placeholder': '您的确认密码', 'autocomplete': 'off'}))
class Meta:
model = models.UserProfile
fields = '__all__' # ['username']
exclude = ['is_active']
widgets = {
'username': forms.EmailInput(attrs={'placeholder': '您的用户名', 'autocomplete': 'off',}),
# 'password':forms.PasswordInput(attrs={'placeholder':'您的密码','autocomplete':'off'}),
'mobile': forms.TextInput(attrs={'placeholder': '您的手机号', 'autocomplete': 'off'}),
'name': forms.TextInput(attrs={'placeholder': '您的真实姓名', 'autocomplete': 'off'})
}
error_messages = {
'username': {
'required': '必填',
'invalid': '邮箱格式不正确'
}
}
def clean(self):
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
# 对密码进行加密
md5 = hashlib.md5()
md5.update(password.encode('utf-8'))
self.cleaned_data['password'] = md5.hexdigest()
return self.cleaned_data
else:
self.add_error('re_password', '两次密码不一致')
raise ValidationError('两次密码不一致!!')
应用
def reg(request):
form_obj = RegForm()
if request.method == 'POST':
form_obj = RegForm(request.POST)
# 对提交的数据进行校验
if form_obj.is_valid():
# 校验成功 把数据插入数据中
# models.UserProfile.objects.create(**form_obj.cleaned_data)
form_obj.save() #这一步直接写入数据库
return redirect(reverse('login'))
print(form_obj.errors)
return render(request, 'reg.html', {'form_obj': form_obj})