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("id","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>