简单操作步骤
1.创建UserForm类,继承forms.Form
class UserForm(dforms.Form):
username = fields.CharField()
email = fields.EmailField()
2.views中引入UserForm
3.在前端创建与Form对应的表单
<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>
4.编写后台代码
def edit_user(request,nid):
if request.method == "GET":
data = models.UserInfo.objects.filter(id=nid).first()
# 这一步必须,创建Form对象,返回给前端
obj = UserForm({'username':data.username,'email':data.email})
return render(request,'edit_user.html',{'obj':obj,'nid':nid})
else:
# 接受表单数据,生成UserForm对象
obj = UserForm(request.POST)
if obj.is_valid():
# 如果验证成功,clean_data就是表单数据的字典形式
models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data)
return redirect('/users/')
else:
return render(request,'edit_user.html',{'obj':obj,'nid':nid})
前端快速生成
- {{ obj_as_p }}
- {{ obj_as_li }}
- {{ obj_as_table }}
Form常用字段
- Field
- 字段
ChoiceField ***** 下拉
MultipleChoiceField 下拉,多选
CharField
IntegerField
DecimalField 小数
DateField
DateTimeField
EmailField
GenericIPAddressField IP
FileField 上传文件
Field本质上是一个widgest插件和一个正则表达式
forms.widgests 定制生成的HTML插件
- 自定义input框中的属性
widget = widgets.TextInput(attrs={'class':'c1'}), # 定制HTML插件
- select下拉框
widget=widgets.Select(choices=[(1,'刚娘'),(2,'铁娘'),(3,'钢弹')])
常用插件
Form实时更新
- 方法一:给自定义Form加上__int__方法,让他每次实例化的时候都重新查询,并且继承父类的__init__方法(推荐)
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})
- 方法二:利用modelField(不推荐,无法自定制)
from django.forms.models import ModelChoiceField
from django.forms.models import ModelChoiceField
class LoveForm(forms.Form):
price = fields.IntegerField()
user_id2 = ModelChoiceField(
queryset=models.UserInfo.objects.all(),
to_field_name='id'
)
注意:依赖models中的str方法
Form自定义验证器
- 根据正则表达式验证
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,'刘皓宸'),(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']
b. 整体错误验证
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
PS: _post_clean
注:重写clean方法是对form整体的进行验证(是为了了出来多个字段连个唯一的场景),他在字段验证之后执行,字段验证的错误信息的key为字段名称,整体验证的错误信息的key为__all__,可以使用obj.error.__all__点出来value
源码:
try:
if isinstance(field, FileField):
initial = self.get_initial_for_field(field, name)
value = field.clean(value, initial)
else:
value = field.clean(value)
self.cleaned_data[name] = value
if hasattr(self, 'clean_%s' % name):
value = getattr(self, 'clean_%s' % name)()
self.cleaned_data[name] = value
except ValidationError as e:
self.add_error(name, e)
form的序列化
- 如果是QuerySet对象数组(如all、filter拿到的等),先使用serialize将对象序列化为字符串添加进字典,再使用json.dumps将字典序列化为json字符串,然后再前端使用JSON.parse方法将该字符串序列化为JSON对象
from django.core import serializers
ret = models.BookType.objects.all()
data = serializers.serialize("json", ret)
result['data'] = data
json.dumps(result)
- 如果对象是QuerySet对象,但里面是字典或者元组这样的python基本类型(如values values_list),只需要使用list()将其转换为python list基本数据类型即可
,然后再使用json.dumps进行转换,且前端不需要parse
import json
#ret = models.BookType.objects.all().values('caption')
ret = models.BookType.objects.all().values_list('caption')
ret=list(ret)
result = json.dumps(ret)
重点:python json.dumps()只能处理基本数据类型
Form 上传文件
注意:request.POST 中存放的参数
request.FILES 中存放的文件
- 自己实现上传
def upload_file(request):
if request.method == 'GET':
return render(request, 'form/upload.html')
else:
file = request.FILES.get('img')
filename = file.name
f = open(filename,"wb")
for line in file.chunks():
f.write(line)
f.close()
return HttpResponse("提交成功")
- 基于Form的上传
from django import forms
from django.forms import fields
class UploadForm(forms.Form):
user = fields.CharField()
img = fields.FileField()
def upload(request):
if request.method == 'GET':
return render(request,'upload.html')
else:
obj = UploadForm(request.POST,request.FILES)
if obj.is_valid():
user = obj.cleaned_data['user']
img = obj.cleaned_data['img']
<!--user = request.POST.get('user')-->
<!--img = request.FILES.get('img')-->
# img是对象(文件大小,文件名称,文件内容。。。)
print(img.name)
print(img.size)
f = open(img.name,'wb')
for line in img.chunks():
f.write(line)
f.close()
return HttpResponse('...')