Django之Form组件
一 Form的功能
- 用户请求数据验证 ***
- 自动生成错误信息
- 打包用户提交的正确信息
- 自动生成HTML标签(可以通过插件设置样式)***
- HTML From提交保留上次提交的数据
二 Form组件的使用
2.1 创建Form类
from django.forms import Form from django.forms import fields class xxx(Form): #必须继承Form xx = fields.CharField(required=True, max_length=None, min_length=None, error_message=None) #required:是否为空 #max_length:最大长度 #min_length:最小长度 #error_message:错误信息
2.2 使用
#创建对象,将数据和规则(类)进行匹配 obj = xxx(request.POST) # 是否校验成功 obj.is_valid() # 所有错误信息 obj.errors # 正确信息 obj.cleaned_data #字典格式
注意:html标签name属性必须等于Form类字段名
2.3 实例
from django.shortcuts import render,redirect from django.forms import Form from django.forms import fields class loginRegisterFrom(Form): '''用户登录注册验证''' # 用户名验证: 不能为空,长度在4-16位 username = fields.CharField( max_length=16, min_length=4, required=True, error_messages={ 'required': '用户名不能为空!', 'min_length': '用户名长度低于4位!', 'max_length': '用户名长度高于16位!', } ) # 邮箱验证: 不能为空 email = fields.EmailField( required=True, error_messages={"required": "邮箱不能为空!", "invalid": "无效的邮箱!"}, ) # 密码验证: 不能为空,长度大于8位 password = fields.CharField( required=True, min_length=8, error_messages={ 'required': '密码不能为空!', 'min_length':'密码长度低于8位' } ) def login(request): '''登录''' if request.method == 'GET': return render(request, 'login_register.html', {'page_name': '登录'}) else: obj = loginRegisterFrom(request.POST) if obj.is_valid(): # 用户输入格式正确 print(obj.cleaned_data) # 字典类型 {'email': '123@qq.com', 'username': 'abcd', 'password': '12345678'} return redirect('http://www.baidu.com') else: # 用户输入格式错误 print(obj.errors) return render(request, 'login_register.html', {'page_name': '登录','obj': obj}) def register(request): '''注册''' if request.method == 'GET': return render(request, 'login_register.html', {'page_name': '注册'}) else: pass
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <form method="post" action="/login/"> {% csrf_token %} <h3>{{ page_name }}</h3> <p><input type="text" name="username" placeholder="用户名">{{ obj.errors.username.0 }}</p> <p><input type="text" name="email" placeholder="邮箱">{{ obj.errors.email.0 }}</p> <p><input type="text" name="password" placeholder="密码">{{ obj.errors.password.0 }}</p> <p><input type="submit" value="提交"></p> </form> </body> </html>
<ul class="errorlist"> <li>email <ul class="errorlist"> <li>无效的邮箱!</li> </ul> </li> <li>username <ul class="errorlist"> <li>用户名长度低于4位!</li> </ul> </li> <li>password <ul class="errorlist"> <li>密码长度低于8位</li> </ul> </li> </ul>
三 Form组件内部原理(简单分析)
借助上面的实例,分析如下:
def login(request):
if request.method == 'GET':
return render(request, 'login_register.html', {'page_name': '登录'})
else:
obj = loginRegisterFrom(request.POST)
'''
1.loginRegisterFrom实例化时,
self.fields={
'username':正则表达式
'email':正则表达式
'password':正则表达式
}
2.循环self.fields
flag = True #校验成功与否初始值
errors #用于收集错误信息
cleaned_data #用于收集正确信息
for k,v in self.fields.items():
k:usernam...
v:正则表达式
input_value = request.POST.get(k)
正则表达式和input_value进行匹配
flag = False
return flag
'''
if obj.is_valid():
# 用户输入格式正确
print(obj.cleaned_data) # 字典类型 {'email': '123@qq.com', 'username': 'abcd', 'password': '12345678'}
return redirect('http://www.baidu.com')
else:
# 用户输入格式错误
print(obj.errors)
return render(request, 'login_register.html', {'page_name': '登录','obj': obj})
四 Form类中的字段、插件
创建Form类时,主要涉及到字段和插件,字段用于对用户请求数据的验证,插件用于自动生成HTML。
4.1 字段
所谓字段,可以理解为不同的字段对应不同的正则表达式,我们可以使用Form中内置的字段以使用其正则表达式,我们也可以通过RegexField()内置字段自定义正则表达式。
Field
required=True, #是否允许为空
widget=None, #HTML插件 *****
label=None, #用于生成Label标签或显示内容
initial=None, #初始值
help_text='', #帮助信息(在标签旁边显示)
error_messages=None, #错误信息 {'required': '不能为空', 'invalid': '格式错误'}
show_hidden_initial=False, #是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
validators=[], #自定义验证规则
localize=False, #是否支持本地化
disabled=False, #是否可以编辑
label_suffix=None #Label内容后缀
CharField(Field)
max_length=None, #最大长度
min_length=None, #最小长度
strip=True #是否移除用户输入空白
IntegerField(Field)
max_value=None, #最大数值
min_value=None, #最小数值
FloatField(IntegerField)
...
DecimalField(IntegerField)
max_value=None, #最大数值
min_value=None, #最小数值
max_digits=None, #最大长度
decimal_places=None, #小数位长度
BaseTemporalField(Field)
input_formats=None #时间格式化
DateField(BaseTemporalField) #格式:2015-09-01
TimeField(BaseTemporalField) #格式:11:12
DateTimeField(BaseTemporalField) #格式:2015-09-01 11:12
DurationField(Field) #时间间隔:%d %H:%M:%S.%f
...
RegexField(CharField)
regex, #自定制正则表达式
max_length=None, #最大长度
min_length=None, #最小长度
error_message=None, #忽略,错误信息使用 error_messages={'invalid': '...'}
EmailField(CharField)
...
FileField(Field)
allow_empty_file=False #是否允许空文件
ImageField(FileField)
...
'''
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
- form表单中 enctype="multipart/form-data"
- view函数中 obj = MyForm(request.POST, request.FILES)
'''
URLField(Field)
...
BooleanField(Field)
...
NullBooleanField(BooleanField)
...
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二次筛选
ModelMultipleChoiceField(ModelChoiceField)
... django.forms.models.ModelMultipleChoiceField
TypedChoiceField(ChoiceField)
coerce = lambda val: val #对选中的值进行一次转换
empty_value= '' #空值的默认值
MultipleChoiceField(ChoiceField)
...
TypedMultipleChoiceField(MultipleChoiceField)
coerce = lambda val: val #对选中的每一个值进行一次转换
empty_value= '' #空值的默认值
ComboField(Field)
fields=() #使用多个验证,如下:即验证最大长度20,又验证邮箱格式
#fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
MultiValueField(Field)
#PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
SplitDateTimeField(MultiValueField)
input_date_formats=None, #格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
input_time_formats=None #格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
FilePathField(ChoiceField) #文件选项,目录下文件显示在页面中
path, #文件夹路径
match=None, #正则匹配
recursive=False, #递归下面的文件夹
allow_files=True, #允许文件
allow_folders=False, #允许文件夹
required=True,
widget=None,
label=None,
initial=None,
help_text=''
GenericIPAddressField
protocol='both', #both,ipv4,ipv6支持的IP格式
unpack_ipv4=False #解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
SlugField(CharField) #数字,字母,下划线,减号(连字符)
...
UUIDField(CharField) #uuid类型
对于以上清单中的参数做如下分类:
- 验证类:required,error_messages,max_length,min_length等
- 生成HTML标签类:widget,label,disable,label_suffix,initial,help_text等
注:UUID是根据MAC以及当前时间等创建的不重复的随机字符串
>>> import uuid # make a UUID based on the host ID and current time >>> uuid.uuid1() # doctest: +SKIP UUID('a8098c1a-f86e-11da-bd1a-00112444be1e') # make a UUID using an MD5 hash of a namespace UUID and a name >>> uuid.uuid3(uuid.NAMESPACE_DNS, 'python.org') UUID('6fa459ea-ee8a-3ca4-894e-db77e160355e') # make a random UUID >>> uuid.uuid4() # doctest: +SKIP UUID('16fd2706-8baf-433b-82eb-8c7fada847da') # make a UUID using a SHA-1 hash of a namespace UUID and a name >>> uuid.uuid5(uuid.NAMESPACE_DNS, 'python.org') UUID('886313e1-3b8a-5372-9b90-0c9aee199e5d') # make a UUID from a string of hex digits (braces and hyphens ignored) >>> x = uuid.UUID('{00010203-0405-0607-0809-0a0b0c0d0e0f}') # convert a UUID to a string of hex digits in standard form >>> str(x) '00010203-0405-0607-0809-0a0b0c0d0e0f' # get the raw 16 bytes of the UUID >>> x.bytes b'\x00\x01\x02\x03\x04\x05\x06\x07\x08\t\n\x0b\x0c\r\x0e\x0f' # make a UUID from a 16-byte string >>> uuid.UUID(bytes=x.bytes) UUID('00010203-0405-0607-0809-0a0b0c0d0e0f')
4.2 插件
TextInput(Input) NumberInput(TextInput) EmailInput(TextInput) URLInput(TextInput) PasswordInput(TextInput) HiddenInput(TextInput) Textarea(Widget) DateInput(DateTimeBaseInput) DateTimeInput(DateTimeBaseInput) TimeInput(DateTimeBaseInput) CheckboxInput Select NullBooleanSelect SelectMultiple RadioSelect CheckboxSelectMultiple FileInput ClearableFileInput MultipleHiddenInput SplitDateTimeWidget SplitHiddenDateTimeWidget SelectDateWidget
注意:若只给定字段,未指定元素或插件,比如:xxx=fields.CharField()里面包含验证规则+HTML标签插件
五 如何保留上次输入的信息
根据目前学习到的知识,实现了数据form表单数据的验证,但是有一个问题,当我们某一项输入错误点击提交后,所有数据被刷新,失去上次内容,那我们怎么保留上次输入内容呢?
5.1 通过Form实现
这里我们需要借助Form组件自动生成HTML标签功能,具体实现如下:
views.py
from django.shortcuts import render,redirect,HttpResponse
from django.forms import Form
from django.forms import fields
class registerFrom(Form):
'''注册验证'''
# 用户名验证: 不能为空,长度在4-16位
username = fields.CharField(
max_length=16,
min_length=4,
required=True,
label='用户名',
#label_suffix=':',
error_messages={
'required': '用户名不能为空!',
'min_length': '用户名长度低于4位!',
'max_length': '用户名长度高于16位!',
}
)
# 邮箱验证: 不能为空
email = fields.EmailField(
required=True,
label='邮箱',
#label_suffix=':',
error_messages={"required": "邮箱不能为空!", "invalid": "无效的邮箱!"},
)
# 密码验证: 不能为空,长度大于8位
password = fields.CharField(
required=True,
min_length=8,
label='密码',
#label_suffix=':',
error_messages={
'required': '密码不能为空!',
'min_length':'密码长度低于8位'
}
)
def register(request):
if request.method == "GET":
obj = registerFrom() # 生成HTML标签<input .... >
return render(request, 'register.html', {'obj':obj})
else:
obj = registerFrom(request.POST) # 生成HTML标签<input .... value=‘xxx'>
if obj.is_valid():
print(obj.cleaned_data)
else:
print(obj.errors)
return render(request, 'register.html', {'obj': obj})
register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form method="post" action="/register/" novalidate>
{% csrf_token %}
{# 方式一:#}
<p>{{ obj.username.label }}{{ obj.username }}{{ obj.errors.username.0 }}</p>
<p>{{ obj.email.label }}{{ obj.email }}{{ obj.errors.email.0 }}</p>
<p>{{ obj.password.label }}{{ obj.password }}{{ obj.errors.password.0 }}</p>
{# 方式二:该方式错误信息在前端以列表的方式显示在input标签的上放#}
{# {{ obj.as_p }}#}
<input type="submit" value="提交" />
</form>
</body>
</html>
<form method="POST" action="/register/"> {% csrf_token %} {{ form.xxoo.label }} {{ form.xxoo.id_for_label }} {{ form.xxoo.label_tag }} {{ form.xxoo.errors }} </form>
注:from表单内加上novalidate参数,取消浏览器的验证功能
5.2 通过Ajax实现
views.py
#registerFrom类同上
def ajax_register(request):
'''aja注册'''
if request.method == 'GET':
return render(request, 'ajax_register.html')
else:
obj = registerFrom(request.POST)
ret = {'status':True, 'msg':None}
if obj.is_valid():
# 用户输入格式正确
print(obj.cleaned_data)
else:
# 用户输入格式错误
#print(obj.errors)
ret = {'status': False, 'msg': obj.errors}
import json
return HttpResponse(json.dumps(ret))
ajax_register.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id='f1' method="post" action="/ajax_register/">
{% csrf_token %}
<h3>{{ page_name }}</h3>
<p><input type="text" name="username" placeholder="用户名"></p>
<p><input type="text" name="email" placeholder="邮箱"></p>
<p><input type="text" name="password" placeholder="密码"></p>
<p><a onclick="submitFrom()">提交</a></p>
</form>
<script src="/static/jquery-3.2.1.js"></script>
<script>
function submitFrom() {
$('.c1').remove();
$.ajax({
url:'/ajax_register/',
type: 'POST',
data: $('#f1').serialize(), //user=alex&pwd=456&csrftoen=dfdf ****
dataType: 'JSON',
success:function (arg) {
if(arg.status){
console.log('ok')
}else {
$.each(arg.msg,function (index,value) {
var tag = document.createElement('span');
tag.innerHTML = value[0];
tag.className = 'c1';
$('#f1').find('input[name="'+ index +'"]').after(tag);
})
}
}
}
)
}
</script>
</body>
</html>
5.3 两种方式类比
From方式:
- 刷新,失去上次内容--借助Form组件自动生成HTML标签功能实现上次数据保留
- 显示错误信息
- 使用验证功能,生成HTML标签功能
Ajax方式:
- 不刷新,上次内容自动保留
- 不显示错误信息--借助js添加错误信息标签
- 仅使用验证功能
六 实例分析
实例地址:待补充
6.1 Form对象添加数据
#Form对象中添加数据时,如果为:
obj = xxxForm(data={‘k1’:’v1’}) #里面包括HTML标签及错误信息(校验)
#如果不需要进行校验,可以写成:
obj = xxxForm(initial={‘k1’:’v1’}),
#obj = xxxForm(request.POST)的本质为:obj = xxxForm(data=request.POST),
6.2 选择框的使用
#单选
#方式一(CharField/IntegerField...+widgets.Select()):
xx = fields.IntegerField(
# widget = widgets.Select(choices = (1,'北京'),(2,'上海'),(3,'深圳'),]) #自定义
widget = widgets.Select(choices = models.Classes.objects.values_list('id','tname'),attrs={'属性名': '属性值'}) #通过数据库获取
)
#注意:widget = widgets.Select(choices=models.Classes.objects.values_list('id','cname'),attrs={‘multiple’: ‘multiple’}) 无用,内部会把他当成单选
#Select内部取值方式为request.POST.get(),只能取一个值
#方式二(ChoiceField+widgets.Select):
xx = fields.ChoiceField(
choices = models.Classes.objects.values_list('id','tname'), #单独一行,不能放在Select中
widget = widgets.Select(attrs = {'属性名': '属性值'}) #通过指定attrs = {'属性名': '属性值'}可控制前端样式,无属性时可不要()
)
#对象初始化(指定默认值):obj = xxxForm({'cls_id':1})
#多选(MulipleChoiceFiled+widgets.SelectMultiple)
xx = fields.MultipleChoiceField(
choices = models.Classes.objects.values_list('id','title'), #单独一行,不能放在Select中
widget = widgets.SelectMultiple #通过指定attrs = {'属性名': '属性值'}可控制前端样式,无属性时可不要()
)
#对象初始化(指定默认值):obj = xxxForm({'cls_id':[1,2,3]})
多选方式的错误示范:
6.3 无法实时获取更新的值bug处理
使用select标签时,需要注意choices的选项可以从数据库中获取,但因为是静态字段无法实时获取更新的值,造成代码bug,有以下两种处理方式。
方式一:自定义构造方法(建议使用)
class studentForm(Form):
sname = fields.CharField(min_length=2,max_length=32)
email = fields.EmailField()
age = fields.IntegerField(min_value=18,max_value=45)
cls_id = fields.IntegerField(
#从数据库中获取选择框数据
#choices = models.Classes.objects.values_list('id', 'cname'), #当加入自定义构造方法后,可省略
widget = widgets.Select
)
def __init__(self, *args, **kwargs):
'''自定义构造方法'''
super(studentForm,self).__init__(*args,**kwargs)
self.fields['cls_id'].widget.choices=models.Classes.objects.values_list('id','cname')
补充说明:
# 当我们创建对象时obj = teacherForm(),程序执行下面2步:
# 1. 找到所有字段
# 2. 将所有字段加入到self.fields中
# self.fields = {
# 字段1: ...
# 字段2: ...
# ... ...
# }
方式二:使用Django提供的ModelChoiceField和ModelMultipleChoiceField字段来实现
from django.forms import models as form_model
class studentForm(Form):
sname = fields.CharField(min_length=2,max_length=32)
email = fields.EmailField()
age = fields.IntegerField(min_value=18,max_value=45)
cls_id = form_model.ModelChoiceField(queryset=models.Classes.objects.all()) #单选使用
#xxxx = form_model.ModelMultipleChoiceField(queryset=models.Classes.objects.all()) #多选使用
但此时存在一个问题,访问时是一个一个对象,需要在models中对Classes做如下修改:
class Classes(models.Model):
cname = models.CharField(max_length=32)
def __str__(self):
return self.cname
6.4 其他知识点补充
1. 创建Form类时,保持字段名与数据库字段名一致
2. zip函数(拉链函数)
>>> a = [(1,2,3),(11,22,33)] >>> list(zip(*a)) [(1, 11), (2, 22), (3, 33)] >>> list(zip(*a))[0] (1, 11)
3. 三元运算
a if a>b else b #如果a>b成立,则为a,否则为b
4. 格式化代码格式:
pycharm中:菜单栏Code—>Reformat Code
七 常用选择插件
class testForm(Form):
# 单radio,值为字符串
x1 = fields.CharField(
initial = 1, #初始选择对象
widget = widgets.RadioSelect(choices=((1, '男'), (2, '女')))
)
# 单radio,值为字符串
x2 = fields.ChoiceField(
choices =((1, '男'), (2, '女')),
initial = 2,
widget = widgets.RadioSelect
)
# 单select,值为字符串
x3 = fields.CharField(
initial = 2,
widget = widgets.Select(choices = ((1, '北京'), (2, '上海'), (3, '深圳')))
)
# 单select,值为字符串
x4 = fields.ChoiceField(
choices = ((1, '北京'), (2, '上海'), (3, '深圳')),
initial = 2,
widget = widgets.Select
)
# 多选select,值为列表
x5 = fields.MultipleChoiceField(
choices = ((1, '北京'), (2, '上海'), (3, '深圳')),
initial = [1,2,],
widget = widgets.SelectMultiple
)
# 单checkbox
x6 = fields.CharField(
widget = widgets.CheckboxInput
)
# 多选checkbox,值为列表
x7 = fields.MultipleChoiceField(
choices = ((1, '北京'), (2, '上海'), (3, '深圳')),
# initial = [2,3,],
widget = widgets.CheckboxSelectMultiple
)
# 文件
x8 = fields.FileField(
widget = widgets.FileInput
)
# 文本框
x9 = fields.CharField(
widget = widgets.Textarea
)
八、扩展方法
8.1 自定义验证规则
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator
class MyForm(Form):
xx = fields.CharField(
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
更多方法可参考:http://www.cnblogs.com/wupeiqi/articles/6144178.html
8.2 方法扩展
寻找路径:
用法示例:
from django.core.exceptions import ValidationError
class registerForm(Form):
'''用户注册'''
user = fields.CharField(min_length=2,max_length=8)
emial = fields.EmailField()
pwd = fields.CharField(min_length=8,max_length=32)
def clean_user(self):
'''第一个钩子函数,针对每一个字段无法用正则验证的其他验证,比如:用户注册判断是否存在于数据库中等'''
v = self.cleaned_data['user']
if models.userInfo.objects.filter(name=v).count():
raise ValidationError('用户名已存在')
return v #必须有返回值,不然返回为None,导致cleaned_data数据清空
def clean_email(self):
'''邮箱处理'''
pass
def clean_pwd(self):
'''密码处理'''
pass
def clean(self):
'''第二个钩子函数,对整体进行额外的验证,比如对用户和邮箱做联合唯一索引'''
user = self.cleaned_data.get('user')
email = self.cleaned_data.get('email')
if models.userInfo.objects.filter(name=user,email=email).count():
raise ValidationError('用户名邮箱已注册') # 视图函数中通过clean_error = form.errors.get("__all__")获得,前端使用clean_error.0
return self.cleaned_data
def _post_clean(self):
'''第三个钩子函数,自定义(不常用)'''
pass
两次密码是否相同的几种验证方式:
# 视图 from django.shortcuts import render, HttpResponse, redirect from django.forms import Form, fields, widgets from django.core.exceptions import ValidationError wid_01 = widgets.TextInput(attrs={"class":"form_control"}) wid_02 = widgets.PasswordInput(attrs={"class":"form_control"}) class UserForm(Form): name = fields.CharField(max_length=32,widget=wid_01) pwd = fields.CharField(max_length=32,widget=wid_02) r_pwd = fields.CharField(max_length=32,widget=wid_02) email = fields.EmailField(widget=wid_01) tel = fields.CharField(max_length=32,widget=wid_01) # 方式一:通过clean_字段名()方式验证 def clean_r_pwd(self): """ 两次密码确认,该方式需要严格按照顺利执行 :return: """ pwd = self.cleaned_data['pwd'] r_pwd = self.cleaned_data['r_pwd'] if pwd == r_pwd: return r_pwd raise ValidationError('方式一:密码不一致') # 方式二:利用clean()+add_error()方式验证 def clean(self): """ 执行完后再执行密码验证 :return: """ pwd = self.cleaned_data['pwd'] r_pwd = self.cleaned_data['r_pwd'] if pwd == r_pwd: # return self.cleaned_data return None self.add_error("r_pwd",ValidationError('方式二:密码不一致')) # 方式三:利用clean(),前端利用clean_error = form.errors.get("__all__")方式验证 def clean(self): pwd = self.cleaned_data.get('pwd') r_pwd = self.cleaned_data.get('r_pwd') if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('方式三:密码不一致') def form_register(request): if request.method == "POST": form = UserForm(request.POST) if form.is_valid(): print(form.cleaned_data) # 所有干净的字段以及对应的值 return HttpResponse("OK") else: clean_error = form.errors.get("__all__") return render(request, "form_register4.html", locals()) form = UserForm() return render(request,"form_register.html",locals()) # 模板 form_register.html <!DOCTYPE> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件--> <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384- BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form method="post" action="" novalidate> <h3>注册</h3> {% csrf_token %} {% for field in form %} <div> <label for="user">{{ field.label }}</label> {{ field }} <span style="color: red"> <!--方式三时加入该段代码--> <!--{% if field.label == "R pwd" %}--> <!--<span>{{ clean_error.0 }}</span>--> <!--{% endif %}--> {{ field.errors.0 }} </span> </div> {% endfor %} <input type="submit" value="提交" class="btn btn-default" /> </form> </div> </div> </div>
说明:locals()
Python 的内建函数 locals() ,它返回的字典对所有局部变量的名称与值进行映射,所以我们在上面示例中可以用locals()替代复杂的{},但是我们需要注意的是它包括所有的局部变量,它们可能比你想让模板访问的要多。 比如:上面的locals()具体如下:
{'request': <WSGIRequest: POST '/form_register2/'>, 'clean_error': ['方式三:密码不一致'], 'form': <UserForm bound=True, valid=False, fields=(name;pwd;r_pwd;email;tel)>}
九 其他
在页面展示方面,有以下两种方式:
方式一:灵活,可以在前端任意布局(推荐使用)
<form>
{{obj.xx}}
{{obj.xx}}
{{obj.xx}}
{{obj.xx}}
</form>
方式二:生成简单,但Form类中需要进行前缀、后缀等设置
//生成p标签
{{obj.as_p}}
//生成ul标签
<ul>
{{obj.as_ul}}
</ul>
//生成table标签
<table>
{{obj.as_table}}
</table>
...




浙公网安备 33010602011771号