27)django-form操作示例(动态Select数据,自定义字段验证,全局验证等)

1)普通传递select数据

    # -*- coding:utf-8 -*-
__author__ = 'shisanjun' from django import forms
from django.forms import fields,widgets class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
) user_type=fields.ChoiceField(
choices=[(1,"普通用户"),(2,"超级用户")],
widget=widgets.Select,
)
<form action='{% url "index" %}' method="post">
<p>
{{ obj.user }}
</p>
<p>{{ obj.pwd }}</p>
<p>{{ obj.user_type }}</p>
</form>

2)上面choice应该从数据库中取数据

from django import forms
from django.forms import fields,widgets
from app01 import models
class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
)
user_type=fields.ChoiceField(
#choices=[(1,"普通用户"),(2,"超级用户")],
choices=models.UserType.objects.all().values_list("id","name"),#要返回元组列表
widget=widgets.Select,
)

3)上面有个问题,就是数据库中新增加的数据,需要重起服务才能加载新数据。

这是什么原因造成的?
上面user,pwd,user_type都是放在类里面的,都是静态字段,数据加载都是一次性加载在内存里面的。 #解决:
def index(request):
from app01 import forms
obj=forms.UserInfoForm()
obj.fields#这里面封装了user,pwd,user_type,当数据库有新的数据的时候从新赋值
obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
return render(request,"index.html",{"obj":obj})

4)上面如果有很多choince,那要写很多,怎么改进(两种方法)

重新构造form的__init__()方法。在init里面赋值上面也是对类对象的实例重新赋值。

#方法1
# -*- coding:utf-8 -*-
__author__ = 'shisanjun' from django import forms
from django.forms import fields,widgets
from app01 import models
class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
)
user_type=fields.ChoiceField(
#choices=[(1,"普通用户"),(2,"超级用户")],
choices=models.UserType.objects.all().values_list("id","name"),
widget=widgets.Select,
) def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name") #方法2 -*- coding:utf-8 -*-
__author__ = 'shisanjun' from django import forms
from django.forms import fields,widgets
from app01 import models
class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
)
  #方法1
user_type=fields.ChoiceField(
#choices=[(1,"普通用户"),(2,"超级用户")],
choices=[],#这里不用赋值,原因实例化的时候init会赋值
widget=widgets.Select,
)
#方法2
user_type2=fields.CharField(widget=widgets.Select(choices=[]))

def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
#方法2
self.fields["user_type2"].widget.choices=models.UserType.objects.all().values_list("i
d","name")

5)上面从数据库取数据也django也可以自己做,但是不太好。

from django.forms.models import ModelChoiceField
user_type3=ModelChoiceField(
queryset=models.UserType.objects.all(),#django会自动取
) 这里是有代价的,要在model里面加__str__,不然显示的名称是对象
class UserType(models.Model):
name=models.CharField(max_length=32)
def __str__(self):
return self.name # -*- coding:utf-8 -*-
__author__ = 'shisanjun' from django import forms
from django.forms import fields,widgets
from app01 import models
from django.forms.models import ModelChoiceField
class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
)
user_type=fields.ChoiceField(
#choices=[(1,"普通用户"),(2,"超级用户")],
choices=[],#这里不用赋值,原因实例化的时候init会赋值
widget=widgets.Select,
)
#方法2
user_type2=fields.CharField(widget=widgets.Select(choices=[])) #方法3
user_type3=ModelChoiceField(
empty_label="请选择",
queryset=models.UserType.objects.all(),#django会自动取
)
def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
#方法2
self.fields["user_type2"].widget.choices=models.UserType.objects.all().
values_list("id","name")

6)默认值

def index(request):
from app01 import forms
obj=forms.UserInfoForm()#如果这里赋值字典就是显示默认值(初始化)
obj.fields#这里面封装了user,pwd,user_type,当数据库有新的数据的时候从新赋值

#obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
return render(request,"index.html",{"obj":obj})

7)用户验证

def index(request):
if request.method=="GET":
obj=forms.UserInfoForm()#如果这里赋值字典就是显示默认值(初始化)
obj.fields#这里面封装了user,pwd,user_type,当数据库有新的数据的时候从新赋值
#obj.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
return render(request,"index.html",{"obj":obj})
elif request.method=="POST":
obj=forms.UserInfoForm(request.POST,request.FILES)
obj.is_valid()#他是基于什么验证的,根据from模板验证。form会为长度,为空等验证,但是如果用户已存在,就不应该进行上面验证。 # -*- coding:utf-8 -*-
__author__ = 'shisanjun' from django import forms
from django.forms import fields,widgets
from app01 import models
from django.forms.models import ModelChoiceField
from django.core.exceptions import ValidationError
class UserInfoForm(forms.Form):
user=fields.CharField(
required=False,
widget=widgets.Textarea(attrs={"class":"c1"}),
)
pwd=fields.CharField(
max_length=12,
widget=widgets.PasswordInput(attrs={"class":"c1"})
)
user_type=fields.ChoiceField(
#choices=[(1,"普通用户"),(2,"超级用户")],
choices=[],#这里不用赋值,原因实例化的时候init会赋值
widget=widgets.Select,
)
#方法2
user_type2=fields.CharField(widget=widgets.Select(choices=[])) #方法3
user_type3=ModelChoiceField(
empty_label="请选择",
queryset=models.UserType.objects.all(),#django会自动取
) def __init__(self,*args,**kwargs):
super(UserInfoForm,self).__init__(*args,**kwargs)
self.fields["user_type"].choices=models.UserType.objects.all().values_list("id","name")
#方法2
self.fields["user_type2"].widget.choices=models.UserType.objects.all().values_list("id","name") class RegiesterForm(forms.Form):
user=fields.CharField()#一个字段一个字段的循环,这里通过了,才会到clean_user,下面以次类推
email=fields.EmailField() def clean_user(self): #通过调用form预留的钩子,clean_user单独对user做验证
c=models.Userinfo.objects.filter(name=self.cleaned_data['user'])
#如果数据库中有,应该给页面报错了,显示用户已存在
if not c:
return self.cleaned_data['user'] #返回原来值
else:
#如果没有抛出valideionError
raise ValidationError("用户名已存在",code="xxx")

def clean_email(self):
pass
    

8)如果用户名不对,错误显示在用户名旁边。(上面是单独给字段写的钩子),也可以对整个form做钩子验证。

class LoginForm(forms.Form):
user=fields.CharField()#一个字段一个字段的循环,这里通过了,才会到clean_user,下面以次类推
pwd=fields.CharField()
email=fields.EmailField() def clean_user(self): #通过调用form预留的钩子,clean_user单独对user做验证
c=models.Userinfo.objects.filter(name=self.cleaned_data['user'])
#如果数据库中有,应该给页面报错了,显示用户已存在
if not c:
return self.cleaned_data['user'] #返回原来值
else:
#如果没有抛出valideionError
raise ValidationError("用户名已存在",code="user")
def clean_email(self):
pass def clean(self): #对整体验证 #判断用户名和密码是否存在
c= models.Userinfo.objects.filter(user=self.cleaned_data["user"],password=self.cleaned_data["pwd"])
if not c:
return self.cleaned_data #源码中self.cleaned_data=cleaned_data
else:
raise ValidationError("用户名或密码错误")

源码中一共有3个钩子

self._clean_fields()对字段验证
self._clean_form()对整体验证
self._post_clean()

form验证经历阶段:数据来了-->到相应的form-->先拿到第一个字段,先进行正则表达式判断完,然后执行字段的钩子,--〉所有字段运行完了到clean(),最后到postclean()

is_valid()--->self.errors-->full_clean -->  self._clean_fields()对字段验证
self._clean_form()对整体验证
self._post_clean()

views中错误信息

#views.py
def register(request):
obj=forms.RegiesterForm(request.POST)
if obj.is_valid(): #下面操作,可以在is_valid做验证
#obj.cleaned_data['']
obj.cleaned_data()
else:
obj.errors
#obj.errors就是个字段,每个字段的错误放在各自的字段里面,整体clean错误放在那里了
from django.core.exceptions import NON_FIELD_ERRORS
"""
'__all__':[],整体的错误信息clean抛出的异常都在这里==〉NON_FIELD_ERRORS
NON_FIELD_ERRORS:[],
'user':['code':required,'message':'xxx'],
'pwd':['code':required,'message':'xxx'], """ account.py
from django.shortcuts import redirect,render,HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
from app01 import models
from django.core.exceptions import ValidationError
import json
class LoginForm(forms.Form):
user=fields.CharField()#一个字段一个字段的循环,这里通过了,才会到clean_user,下面以次类推
pwd=fields.CharField()
email=fields.EmailField() def clean_user(self): #通过调用form预留的钩子,clean_user单独对user做验证
c=models.Userinfo.objects.filter(name=self.cleaned_data['user'])
#如果数据库中有,应该给页面报错了,显示用户已存在
if not c:
return self.cleaned_data['user'] #返回原来值
else:
#如果没有抛出valideionError
raise ValidationError("用户名已存在",code="user")
def clean_email(self):
pass
#
# def clean(self): #对整体验证
#
# #判断用户名和密码是否存在
# c= models.Userinfo.objects.filter(user=self.cleaned_data["user"],password=self.cleaned_data["pwd"])
# if not c:
# return self.cleaned_data #源码中self.cleaned_data=cleaned_data
# else:
# ValidationError("用户名或密码错误") class JsonCustomEncoder(json.JSONEncoder):
from django.core.exceptions import ValidationError
def default(self, field):
if isinstance(field,ValidationError):
return {'code':field.code,'message':field.messages}
else:
return json.JSONEncoder.default(self,field)
def login(request):
res={"status":False,"data":None,"error":None}
if request.method=="GET":
return render(request,"login.html")
elif request.method=="POST":
obj=LoginForm(request.POST)
if obj.is_valid():
print(obj.cleaned_data)
res["status"]=True
else:
#res["error"]=obj.errors.as_json()
#为什么不用as_json,as_json返回的是字典,所以res就会变成嵌套字典,json不能转嵌套字典,下面用as_data()结合cls定制
#print(obj.errors.as_data())#errors.as_data()返回的是 ValidationError类型,不是字典,不能直接序列化
res["error"]=obj.errors.as_data()
result=json.dumps(res,cls=JsonCustomEncoder)#dumps有个参数cls,可以定制 return HttpResponse(json.dumps(result)) #obj.errors返回的是ErrorDict,不是字典(虽然继承字典)
#obj.errors.as_json() 返回的字符串(前端要连续反解两次)
#obj.errors.as_data() 返回原生的字典 但是返回value 是ValidationError,不能直接序列化

模板
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<form id="fm">
{% csrf_token %}
<p>
<input type="text" name="username">
</p>
<p>
<input type="text" name="password">
</p>
<a id="submit">提交</a>
</form>
<script src="/static/jquery-1.12.4.js"></script>
<script>
$(function(){
//框架自加载
$("#submit").click(
function(){
$.ajax(
{
url:"{% url 'login' %}",
type:"post",
data:$("#fm").serialize(),
success:function(arg){
arg=JSON.parse(arg);
console.log(arg);
},
error:function(arg){
console.log(arg);
} }
)
}
)
})
</script>
</body>
上一篇:jquery实现select数据回显


下一篇:phpstorm运行命令行提示‘php‘不是内部或外部命令(2021解决办法)