二十三、Django之Form组件
Django的Form:
1、对用户请求的验证
2、生成HTML代码
a、创建一个类
b、类中创建字段(包含正则表达式)
c、Get
a) Obj = Fr()
obj.user=> 自动生成HTML
d、POST
a) Obj = Fr(request,POST)
i. If obj.is_valid():
Obj.cleaned_data
Else:
Obj.errors
Return .....obj
1、Form的使用
from django.shortcuts import render, HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
class TestForm(forms.Form):
user=fields.CharField(
required=True, #是否必填
max_length=12, #最大长度
min_length=3, #最小长度
error_messages={
'required':'用户名不能为空',
'max_length':'太长了',
'min_length':'太短了',
}, #错误提示
# widget=widgets.Select(), #定制HTML插件
label='用户名',
initial='xx',
help_text='helptext',
# show_hidden_initial=True,
# validators=[], #自定制验证规则
# disabled=False,
label_suffix='->',
)
age=fields.IntegerField(
label='年龄',
max_value=12,
min_value=5,
)
email=fields.EmailField(
label='邮箱',
)
img=fields.ImageField()
city=fields.ChoiceField(
choices=[(1,'北京'),(2,'上海'),(3,'深圳')],
initial=3, #默认值
)
city2=fields.CharField(
widget=widgets.Select(choices=[(1,'北京'),(2,'上海'),(3,'深圳')])
)
city3 = fields.IntegerField(
widget=widgets.Select(choices=[(1, '北京'), (2, '上海'), (3, '深圳')])
)
hobby=fields.MultipleChoiceField(
choices=[(1,'跑'),(2,'跳'),(3,'游'),(4,'飞')],
initial=[1,3,4],
)
anotherCity=fields.TypedChoiceField(
coerce=lambda x:int(x), # 设置coerce函数,将输出的值转换成需要的类型
choices=[(1, '北京'), (2, '上海'), (3, '深圳')],
initial=3, # 默认值
)
fp=fields.FilePathField(
path='app01'
)
def test(request):
if request.method=='GET':
obj=TestForm()
return render(request,'test.html',{'obj':obj})
else:
obj=TestForm(request.POST,request.FILES)
obj.is_valid()
print(obj.cleaned_data)
return render(request,'test.html',{'obj':obj})
<body>
<form action="/test/" method="post" novalidate enctype="multipart/form-data">
<p>{{ obj.user.label }}{{ obj.user }}</p>
<p>{{ obj.age.label }}{{ obj.age }}{{ obj.errors.age.0 }}</p>
<p>{{ obj.email.label }}{{ obj.email }}</p>
<p>{{ obj.img.label }}{{ obj.img }}</p>
<p>{{ obj.city.label }}{{ obj.city }}</p>
<p>{{ obj.city2.label }}{{ obj.city2 }}</p>
<p>{{ obj.city3.label }}{{ obj.city3 }}</p>
<p>{{ obj.hobby.label }}{{ obj.hobby }}</p>
<p>{{ obj.anotherCity.label }}{{ obj.anotherCity }}</p>
<p>{{ obj.fp.label }}{{ obj.fp }}</p>
<input type="submit" value="提交">
</form>
</body>
form元素的novalidate标识:取消浏览器对数据的验证,交由后台验证数据。
models.UserInfo.objects.create(fm_obj.cleaned_data) 😗*
# Form与Model的字段名保持一致
from django.db import models
class UserInfo(models.Model):
username=models.CharField(max_length=32)
email=models.EmailField(max_length=32)
-----------
from django import forms as dforms
from django.forms import fields
class UserForm(dforms.Form):
username=fields.CharField()
email=fields.EmailField()
-----------
# form数据与model数据就方便转换
def add_user(request):
if request.method == 'GET':
fr_obj = UserForm()
return render(request,'add_user.html',{'fm_obj':fr_obj})
else:
fm_obj = UserForm(request.POST)
if fm_obj.is_valid():
models.UserInfo.objects.create(**fm_obj.cleaned_data)
return redirect('/users/')
else:
return render(request,'add_user.html',{'fm_obj':fm_obj})
def edit_user(request,nid):
if request.method == 'GET':
data = models.UserInfo.objects.filter(id=nid).first()
fm_obj = UserForm({'username':data.username,'email':data.email})
return render(request, 'edit_user.html', {'obj': fm_obj, 'nid': nid})
else:
obj = UserForm(request.POST)
if obj.is_valid():
models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
return redirect('/users/')
else:
return render(request,'edit_user.html',{'obj':obj,'nid':nid})
2、进阶
# 表单数据实时更新
from app01 import models
from django.forms.models import ModelChoiceField
class LoveForm(forms.Form):
# price user_id 为静态字段,在程序加载时创建。
# 因此程序启动之后,UserInfo数据库的数据如果有变化,user_id的选项并不会实时变化。
# 必须重启后台程序。这样设计是不合理的。
price=forms.IntegerField()
user_id=forms.ChoiceField(
#重写了__init__方法后,这里choices不需要赋值了
# choices=models.UserInfo.objects.values_list('id','username')
)
# 继承初始化方法,在每次网络请求时创建Form对象的时候通过self.fields['user_id'].widget.choices重新从数据库取值
def __init__(self,*args,**kwargs):
super(LoveForm,self).__init__(*args,**kwargs)
self.fields['user_id'].widget.choices=models.UserInfo.objects.values_list('id','username')
实时更新方式2(不推荐)
方式2:ModelChoiceField。
不推荐,耦合度高,需要写__str__方法来定选择框显示的内容
...
user_id2=ModelChoiceField(
queryset=models.UserInfo.objects.all(),
to_field_name='id'
)
...
class UserInfo(models.Model):
...
def __str__(self):
return self.username
3、Form的数据验证
class AjaxForm(forms.Form):
username=forms.CharField()
user_id=forms.ChoiceField(
choices=[(0,'Java'),(1,'PHP'),(2,'Python'),(3,'GO')]
)
# 自定义clean_字段名方法
# 必须返回值self.cleadned_data['username']
# 如果出错:raise ValidationError
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 报错
# 自己详细错误信息
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
raise ValidationError('用户名已存在')
return v
# 数据整体验证 抛出的错误会放在__all__列表中,而非某字段名的列表中。
def clean(self):
value_dict=self.cleaned_data
v1=value_dict.get('username')
v2=value_dict.get('user_id')
if v1=='root'and v2=='1':
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
raise ValidationError('整体错误信息')
return self.cleaned_data
def ajax(request):
if request.method=='GET':
obj=AjaxForm()
return render(request,'ajax.html',{'obj':obj})
else:
import json
obj=AjaxForm(request.POST)
if obj.is_valid():
return HttpResponse(json.dumps({'status':100,'message':obj.cleaned_data}))
else:
return HttpResponse(json.dumps({'status':111,'message':obj.errors}))
从Form的is_vaild()函数进入源码,可知有clean_***、clean等数据验证函数提供重写自定义。
4、as_p、as_ul、as_table
<body>
// {{ form_obj.as_p }}
// {{ form_obj.as_ul }}
{{ form_obj.as_table }}
</body>
这几种方式都可以直接生成页面。但推荐的是:
<body>
<form action="/edit_user-{{ nid }}/" method="post" novalidate>
<p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
<p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交"/>
</form>
</body>
5、FileField、ImageField
使用这两个字段时,
form表单中 enctype="multipart/form-data",
view函数中 obj = MyForm(request.POST, request.FILES)
6、ComboField
多个验证
a = fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])