django之form组件
一、验证功能
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm" action="/f1.html/" method="POST">
<p><input type="text" name="user">{{ obj.errors.user.0 }}</p>
<p><input type="text" name="pwd">{{ obj.errors.pwd.0 }}</p>
<p><input type="text" name="age">{{ obj.errors.age.0 }}</p>
<p><input type="text" name="email">{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交" />
</form>
<script src="/static/jquery-3.1.1.js"></script>
</body>
</html>
views
from django.shortcuts import render
from django.shortcuts import HttpResponse,redirect
from django import forms
from django.forms import fields
class F1Form(forms.Form):
user = fields.CharField(
max_length=20,
min_length=2,
required=True,
error_messages={'required':'用户名不能为空','max_length':'不能超过20个字','min_length':'不能小于2个字'}
)
pwd = fields.CharField(required=True,min_length=8)
age = fields.IntegerField(
required=True,
error_messages={
'required':'不能为空',
'invalid':'格式错误'
}
)
email = fields.EmailField(
required=True,
min_length=8,
error_messages={
'invalid':'格式错误'
}
)
def f1(request):
if request.method == 'GET':
obj = F1Form()
return render(request,'f1.html',{'obj':obj})
else:
obj = F1Form(request.POST)
if obj.is_valid():
print('验证成功',obj.cleaned_data)
return HttpResponse('ok')
else:
print('验证失败',obj.errors)
return render(request,'f1.html',{'obj':obj})
二、生成html
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm" action="/f1.html/" method="POST">
<p>{{ obj.user }}{{ obj.errors.user.0 }}</p>
<p>{{ obj.pwd }}{{ obj.errors.pwd.0 }}</p>
<p>{{ obj.age }}{{ obj.errors.age.0 }}</p>
<p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交" />
</form>
<script src="/static/jquery-3.1.1.js"></script>
</body>
</html>
views
from django.shortcuts import render
from django.shortcuts import HttpResponse,redirect
from django import forms
from django.forms import fields
class F1Form(forms.Form):
user = fields.CharField(
max_length=20,
min_length=2,
required=True,
error_messages={'required':'用户名不能为空','max_length':'不能超过20个字','min_length':'不能小于2个字'}
)
pwd = fields.CharField(required=True,min_length=8)
age = fields.IntegerField(
required=True,
error_messages={
'required':'不能为空',
'invalid':'格式错误'
}
)
email = fields.EmailField(
required=True,
min_length=8,
error_messages={
'invalid':'格式错误'
}
)
def f1(request):
if request.method == 'GET':
obj = F1Form() #自动生成html
return render(request,'f1.html',{'obj':obj})
else:
obj = F1Form(request.POST)
if obj.is_valid():
print('验证成功',obj.cleaned_data)
return HttpResponse('ok')
else:
print('验证失败',obj.errors)
return render(request,'f1.html',{'obj':obj})
三、简单应用
models
from django.db import models
class UserInfo (models.Model):
username = models.CharField (max_length=30)
email = models.EmailField (max_length=50)
url
from django.conf.urls import url
from django.contrib import admin
from app01 import views
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^users/', views.users),
url(r'^add_user/', views.add_user),
url(r'^edit_user-(\d+)/', views.edit_user),
]
users.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<a href="/add_user/">添加</a>
<ul>
{% for row in data %}
<li>{{ row.id }}--{{ row.username }}--{{ row.email }}<a href="/edit_user_{{ row.id }}">编辑</a></li>
{% endfor %}
</ul>
</body>
</html>
add_user.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/add_user/" method="post" novalidate>
{% csrf_token %}
<p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
<p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit" value="提交">
</form>
</body>
</html>
edit.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form action="/edit_user_{{ nid }}/" method="post" novalidate>
{% csrf_token %}
<p>{{ obj.username }}{{ obj.errors.username.0 }}</p>
<p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
<input type="submit">
</form>
</body>
</html>
df
from django import forms
from django.forms import fields
class UserForm(forms.Form):
username = fields.CharField()
email = fields.EmailField()
views
from django.shortcuts import render,redirect
from app01 import models
from app01.df import UserForm
def users(request):
data = models.UserInfo.objects.all()
return render(request,'users.html',{'data':data})
def add_user(request):
if request.method == 'GET':
obj = UserForm()
return render(request,'add_user.html',{'obj':obj})
else:
obj = UserForm(request.POST)
if obj.is_valid():
models.UserInfo.objects.create(**obj.cleaned_data)
return redirect('/users/')
else:
return render(request,'add_user.html',{'obj':obj})
def edit_user(request,nid):
if request.method =='GET':
data = models.UserInfo.objects.filter(id=nid).first()
obj =UserForm({'username':data.username,'email':data.email})
return render(request,'edit_user.html',{'obj':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})
四、组件字段
字段主要由正则匹配和插件构成
Field参数
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
(1)CharField参数
具备Field参数
max_length=None, min_length=None, strip=True, empty_value=''
from django.shortcuts import render
from django import forms
from django.forms import fields,widgets
class TestForm(forms.Form):
user = fields.CharField(
required=True, #是否必填
max_length=12, #最大长度
min_length=3, #最小长度
error_messages={}, #错误提示
# widgets = widgets.Select() ,#定制HTML插件
label='用户名',
initial='请输入用户名', #初始化
help_text='无用参数',
show_hidden_initial=False, #输入框不可修改
disabled=True,
label_suffix='-->'
)
age = fields.IntegerField()
email = fields.EmailField()
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})
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<table>
{{ obj.as_table }}
</table>
<ul>
{{ obj.as_ul }}
</ul>
{{ obj.as_p }}
</body>
</html>
显示
(2)IntegerField
具备Field参数
max_value=None, min_value=None
(3)其他
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类型
比较常用:
ChoiceField
MultipleChoiceField
CharField
IntegerField
DecimalField
DateField
DateTimeField
EmailField
GenericIPAddressField
FileField
RegexField
五、字段插件
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
常用插件
# 单radio,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),)) # ) # 单radio,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.RadioSelect # ) # 单select,值为字符串 # user = fields.CharField( # initial=2, # widget=widgets.Select(choices=((1,'上海'),(2,'北京'),)) # ) # 单select,值为字符串 # user = fields.ChoiceField( # choices=((1, '上海'), (2, '北京'),), # initial=2, # widget=widgets.Select # ) # 多选select,值为列表 # user = fields.MultipleChoiceField( # choices=((1,'上海'),(2,'北京'),), # initial=[1,], # widget=widgets.SelectMultiple # ) # 单checkbox # user = fields.CharField( # widget=widgets.CheckboxInput() # ) # 多选checkbox,值为列表 # user = fields.MultipleChoiceField( # initial=[2, ], # choices=((1, '上海'), (2, '北京'),), # widget=widgets.CheckboxSelectMultiple # )
choices选项从数据库中自动更新
方式一
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
user = fields.ChoiceField(
# choices=((1, '上海'), (2, '北京'),),
initial=2,
widget=widgets.Select
)
def __init__(self, *args, **kwargs):
# 拷贝所有的静态字段,复制给self.fields
super(MyForm,self).__init__(*args, **kwargs)
# self.fields['user'].widget.choices = ((1, '上海'), (2, '北京'),)
# 或
self.fields['user'].widget.choices = models.Classes.objects.all().value_list('id','caption')
方式二
rom django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator
class FInfo(forms.Form):
authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
# authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())
ajax提交后只能接受后端字符串,不会接受后端的跳转,也就只能在前端设置跳转。所以ajax提交错误信息要自己展示,跳转要自己跳转。
views
def ajax(request):
if request.method == 'GET':
obj = AjaxForm()
return render(request,'ajax.html',{'obj':obj})
else:
ret = {'status':'no','message':None}
import json
obj = AjaxForm(request.POST)
if obj.is_valid():
ret['status'] = 'yes'
return HttpResponse(json.dumps(ret))
else:
# print(type(obj.errors))
# print(obj.errors)
from django.forms.utils import ErrorDict
# print(obj.errors.as_ul())
# print(obj.errors.as_json())
# print(obj.errors.as_data())
ret['message'] = obj.errors
# 错误信息显示在页面上
return HttpResponse(json.dumps(ret))
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm" method="POST" action="/ajax/">
{% csrf_token %}
{{ obj.as_p }}
<input type="button" value="Ajax提交" id="btn" />
</form>
<script src="/static/jquery-3.1.1.js"></script>
<script>
$(function () {
$('#btn').click(function () {
$.ajax({
url: '/ajax/',
type: 'POST',
data: $('#fm').serialize(),
dataType: 'JSON',
success:function (arg) {
// arg: 状态,错误信息
if (arg.status == 'yes'){
window.location.href = "http://www.baidu.com"
}
console.log(arg);
}
})
})
})
</script>
</body>
</html>
六、简单扩展
1,插件扩展
自定制验证规则
利用Form组件自带的正则扩展:
a. 方式一
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(
error_messages={'invalid': '...'},
validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],
)
b. 方式二
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.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})
2.基于源码流程
验证数据库中是否存在同名用户
a. 单字段
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'BOB'),(2,'ALICE'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']
b. 整体错误验证
class AjaxForm(forms.Form):
username = fields.CharField()
user_id = fields.IntegerField(
widget=widgets.Select(choices=[(0,'alex'),(1,'BOB'),(2,'ALICE'),])
)
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
def clean_username(self):
v = self.cleaned_data['username']
if models.UserInfo.objects.filter(username=v).count():
# 整体错了
# 自己详细错误信息
raise ValidationError('用户名已存在')
return v
def clean_user_id(self):
return self.cleaned_data['user_id']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:
raise ValidationError('整体错误信息')
return self.cleaned_data
PS: _post_clean
七、序列化
from django.shortcuts import render
from django.shortcuts import HttpResponse
from app01 import models
import json
def xuliehua(request):
return render(request,'xuliehua.html')
"""
def get_data(request):
user_list = models.UserInfo.objects.all()
return render(request,'get_data.html',{'user_list':user_list})
"""
def get_data(request):
from django.core import serializers
ret = {'status':True,'data':None}
try:
# user_list = models.UserInfo.objects.all()
# QuerySet【obj,obj,obj】
# ret['data'] = serializers.serialize("json",user_list)
# // var
# v = JSON.parse(arg.data);
# // console.log(v);
# user_list = models.UserInfo.objects.all().values('id','username')
# ret['data'] = list(user_list)
# console.log(arg.data);
# user_list = models.UserInfo.objects.all().values_list('id', 'username')
# ret['data'] = list(user_list)
# console.log(arg.data);
pass
except Exception as e:
ret['status'] = False
result = json.dumps(ret)
return HttpResponse(result)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<h1>用户列表</h1>
<table id="tb">
</table>
<script src="/static/jquery-3.1.1.js"></script>
<script>
$(function () {
initData();
});
function initData() {
$.ajax({
url :'/get_data/',
type:'GET',
dataType:'JSON',
success:function (arg) {
//$('#tb').append(arg);
if(arg.status){
console.log(arg.data);
//var v = JSON.parse(arg.data);
//console.log(v);
}
}
})
}
</script>
</body>
</html>