此文是简单翻译http://www.cnblogs.com/wupeiqi/articles/6144178.html 如有不懂看这个网址把,不过加了代码应该能看懂
Django的Form主要具有一下几大功能:
- 生成HTML标签
- 验证用户数据(显示错误信息)
- HTML Form提交保留上次提交数据
- 初始化页面显示内容
区别:
- form表单(验证;保留上次内容)
-
- Ajax(验证;无需上次内容)
- 返回HttpResponse
- 前端:跳转或错误信息
在form表单里加 novalidate 浏览器报错取消
cleaned_data 就是读取表单返回的值,返回类型为字典dict型
email=cleaned_data['email'] 读取name为 ‘email’的表单提交值,并赋予 email变量
一。熟悉Form类
1.创建Form类
from django.forms import Form
from django.forms import widgets
from django.forms import fields
class MyForm(Form):
user = fields.CharField(
widget=widgets.TextInput(attrs={'id': 'i1', 'class': 'c1'})
)
gender = fields.ChoiceField(
choices=((1, '男'), (2, '女'),),
initial=2,
widget=widgets.RadioSelect
)
city = fields.CharField(
initial=2,
widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)
pwd = fields.CharField(
widget=widgets.PasswordInput(attrs={'class': 'c1'}, render_value=True)
)
2、View函数处理
from django.shortcuts import render, redirect
from .forms import MyForm
def index(request):
if request.method == "GET":
obj = MyForm() #生成html
return render(request, 'index.html', {'form': obj})
elif request.method == "POST":
obj = MyForm(request.POST, request.FILES)
if obj.is_valid(): #判断是否验证成功
values = obj.clean()
print(values)
else:
errors = obj.errors
print(errors)
return render(request, 'index.html', {'form': obj})
else:
return redirect('http://www.google.com')
3.生成HTML
<form action="/" method="POST" enctype="multipart/form-data">
<p>{{ form.user }} {{ form.user.errors }}</p>
<p>{{ form.gender }} {{ form.gender.errors }}</p>
<p>{{ form.city }} {{ form.city.errors }}</p>
<p>{{ form.pwd }} {{ form.pwd.errors }}</p>
<input type="submit"/>
</form>
form.gender.errors显示的是错误信息,有很多错误信息的话form.gender.errors.0 加个.0显示第一个
二。Form类
创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;
1、Django内置字段如下(捡几个重要的)
a.
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内容后缀
b.
CharField(Field)
max_length
=
None
, 最大长度
min_length
=
None
, 最小长度
strip
=
True
是否移除用户输入空白
c.
IntegerField(Field)
FloatField(IntegerField) :这是浮点型的字段,继承了IntegerField
max_value
=
None
, 最大值
min_value
=
None
, 最小值
d.
RegexField(CharField)
regex, 自定制正则表达式
max_length
=
None
, 最大长度
min_length
=
None
, 最小长度
error_message
=
None
, 忽略,错误信息使用 error_messages
=
{
'invalid'
:
'...'
}
e.
FileField(Field)
allow_empty_file
=
False
是否允许空文件
ImageField(FileField)
...
注:需要PIL模块,pip3 install Pillow
以上两个字典使用时,需要注意两点:
-
form表单中 enctype
=
"multipart/form-data"
-
view函数中 obj
=
MyForm(request.POST, request.FILES)
f。
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
①。在app里创建应该forms.py文件,里面创建form类
from django import forms as dforms
from django.forms import fields
class UserForm(dforms.Form):
username = fields.CharField()
email = fields.EmailField()
②。在views下写入相对应的函数
from django.shortcuts import render
from django.shortcuts import redirect
from app01 import models
def users(request):
user_list = models.UserInfo.objects.all()
return render(request,'users.html',{'user_list':user_list})
from app01.forms import UserForm
# url(r'^add_user/', views.add_user),
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})
# url(r'^edit_user-(\d+)/', views.edit_user),
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})
?。前端页面
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_user.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" value="提交" />
</form>
</body>
</html>
2.常用选择插件
# 单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
# )
举例:
传文件、图片的例子:
创建form类
from django.shortcuts import render
from django.shortcuts import redirect
from django.shortcuts import 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={}, # 错误提示
widget = widgets.TextInput(attrs={'class':'c1'}), # 定制HTML插件
label='用户名',
initial='请输入用户',
help_text='asdfasdf',
show_hidden_initial=False,
# validators=[]
disabled=True,
label_suffix='->'
)
age = fields.IntegerField(
label='年龄',
max_value= 12,
min_value=5,
error_messages={
'max_value':'太大了'
}
)
email = fields.EmailField(
label='邮箱'
)
img = fields.FileField()
city = fields.TypedChoiceField(
coerce=lambda x: int(x),
choices=[(1,'上海',),(2,'北京'),(3,'沙河'),],
initial=2
)
hobby = fields.MultipleChoiceField(
choices=[(1,'刚娘'),(2,'铁娘'),(3,'钢弹')],
initial=[1,2]
)
传文件时在form表单后面加
enctype="multipart/form-data"
表示后端能接收到文件类型的 数据
def test(request):
if request.method == 'GET':
#obj = TestForm({'city':3})
obj = TestForm()
txt = "<input type='text' />"
from django.utils.safestring import mark_safe
txt = mark_safe(txt)#这样设置后就不要在前端页面加safe了
return render(request,'test.html',{'obj':obj,'txt':txt})
else:
obj = TestForm(request.POST,request.FILES) #多添加了一个文件参数
obj.is_valid()
print(obj.cleaned_data)
return render(request, 'test.html', {'obj': obj})
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
{{ txt }}
{# enctype="multipart/form-data" 表示后端能接收到文件类型的 数据#}
<form method="POST" action="/test/" novalidate enctype="multipart/form-data">
{% csrf_token %}
<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.hobby.label }}{{ obj.hobby }}</p>
<p>{{ obj.xdb.label }}{{ obj.xdb }}</p>
<input type="submit" value="提交"/>
</form>
</body>
</html>
修改数据不用重启服务直接显示
from app01 import models
from django.forms.models import ModelChoiceField
#像price user_id都是静态属性,程序一运行就在内存中不变了
#所以要加 def __init__ 拷贝所有的静态字段,复制给self.fields
class LoveForm(forms.Form):
price = fields.IntegerField()
user_id = fields.IntegerField(
# widget=widgets.Select(choices=[(0,'alex'),(1,'刘皓宸'),(2,'杨建'),])
widget=widgets.Select()
)
user_id2 = ModelChoiceField(
queryset=models.UserInfo.objects.all(),
to_field_name='id'
)
def __init__(self,*args,**kwargs):
# 拷贝所有的静态字段,复制给self.fields
super(LoveForm,self).__init__(*args,**kwargs)
self.fields['user_id'].widget.choices = models.UserInfo.objects.values_list('id', 'username')
def love(request):
obj = LoveForm()
return render(request,'love.html',{'obj':obj})
利用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': '...'})
自定制匹配规则(ajax):
# 自定义方法 clean_字段名
# 必须返回值self.cleaned_data['username']
# 如果出错:raise ValidationError('用户名已存在')
as_p表示把form表单在前端页面渲染成p标签的形式展示,此外还有as_ul,as_table等。
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,'刘皓宸'),(2,'杨建'),])
)
# 自定义方法 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
def ajax(request):
if request.method == 'GET':
obj = AjaxForm()
return render(request,'ajax.html',{'obj':obj})
else:
ret = {'status':'杨建','message':None}
import json
obj = AjaxForm(request.POST)
if obj.is_valid():
# 跳转到百度
# return redirect('http://www.baidu.com')
# if ....
# obj.errors['username'] = ['用户名已经存在',]
# if ....
# obj.errors['email'] = ['用户名已经存在',]
ret['status'] = '钱'
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())
"""
{
__all__: [],
username:[]
}
"""
ret['message'] = obj.errors
# 错误信息显示在页面上
return HttpResponse(json.dumps(ret))
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm" method="POST" action="/ajax/">
{% csrf_token %}
{# as_p表示把form表单在前端页面渲染成p标签的形式展示,此外还有as_ul,as_table等。#}
{{ 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 == '钱'){
window.location.href = "http://www.baidu.com"
}
console.log(arg);
}
})
})
})
</script>
</body>
</html>