form元件, ModelForm元件
阿新 • • 發佈:2018-11-11
一:form元件功能
form 元件:
1.效驗
2.頁面顯示錯誤資訊
3.渲染頁面
4.只要錯誤資訊重置
二: form元件的語法:
fm=BookForm({"title":"yuan","price":123,"email":"123"}) fm.is_valid() # 如果效驗失敗就返回False # 如果效驗成功就返回True fm.cleaned_data 返回校成功的資料 {對的資料的鍵值:對的資料的值} fm.errors 返回效驗錯誤的資料,後面是列表 {'錯的鍵值':['錯誤資訊',]} 必須先is_valid 才能取出對的和錯的資料
注意:
form表單裡的所有欄位必須給值,如果不給值就會報錯,但是如果給的多就不會報錯,
clean-data裡只有效驗成功的欄位
三.form 元件應用
例項:註冊使用者
模型:model.py
class UserInfo(models.Model): user=models.CharField(max_length=32) pwd=models.CharField(max_length=32) email=models.CharField(max_length=32)
form元件: (寫在哪個裡都可以)
from django.forms import widgets(需要匯入)
class UserForm(forms.Form): msg = {"required": '該欄位不能為空', "invalid": "格式錯誤", "min_length": "長度不可以小於五"} # invalid只適用於郵箱 # error_messages 自定義錯誤資訊,label 自定義lable顯示文字 user = forms.CharField(min_length=5, error_messages=msg, label='使用者名稱', widget=widgets.TextInput(attrs={"class": "form-control"})) pwd = forms.CharField(min_length=5, error_messages=msg, label='密碼', widget=widgets.PasswordInput(attrs={"class": "form-control"})) r_pwd=forms.CharField(error_messages=msg, label='確認密碼', widget=widgets.PasswordInput(attrs={"class": "form-control"})) email = forms.EmailField(error_messages=msg, label='郵箱', widget=widgets.EmailInput(attrs={"class": "form-control"}))
檢視函式:
方式一:
views,py裡
def reg(request): if request.method=="GET": return render(request,'reg.html') if request.method=="POST": # 資料校驗 # 直接把它放進來做校驗就可以request裡多一個crsf-token也沒事多餘一個也不會報錯 form=UserFrom(request.POST) if form.is_valid(): print(form.cleaned_data) else: print("來自errorcleaned",form.cleaned_data) print("哈哈",form.errors) # 因為後面是列表所以需要 # print('哈哈1',form.errors.get('user')[0]) error=form.errors return render(request,"reg.html",{'error':error})
對應的模板裡HTML
# novalidate 讓瀏覽器對你放行不進行攔截 <form action="" method="post" novalidate> {% csrf_token %} <p>使用者名稱<input type="text" name="user"></p><span class="error">{{ error.user.0 }}</span> <p>密碼<input type="password" name="'pwd"></p><span class="error">{{ error.pwd.0 }}</span> <p>郵箱<input type="text" name="email"></p><span class="error">{{ error.email.0 }}</span> <p><input type="submit"></p> </form>
方式二:
views.py
def reg(request): if request.method=="POST": form = UserFrom(request.POST) if form.is_valid(): print(form.cleaned_data) else: error = form.errors return render(request,'reg.html',locals()) form=UserFrom() return render(request, "reg.html", locals())
模板:
# 不能對應加錯誤 <form action="" method="post"> {% csrf_token %} {{ form.as_p }} <p><input type="submit"></p> </form>
方式三:
模板:
方式三直接傳過來,對的不會重置 <form action="" method="post" novalidate> {% csrf_token %} <p>使用者名稱{{ form.user }}</p><span class="error">{{ error.user.0 }}</span> <p>密碼{{ form.pwd }}</p><span class="error">{{ error.pwd.0 }}</span> <p>郵箱{{ form.email }}</p><span class="error">{{ error.email.0 }}</span> <p><input type="submit"></p> </form>
方式四:
模板:
{#方式四#} {#用最後這個就行#} <form action="" method="post" novalidate> {% csrf_token %} {% for field in form %} <div> <lable for=''>{{ field.label }}</lable> {{ field }}<span class="error">{{ field.errors.0 }}</span> </div> {% endfor %} <div><input type="submit">提交</div> </form>
field就是:{{form.user}}
form 元件的使用流程:
原始碼解析is_valid(self)#self是自定義元件物件
self._errors = ErrorDict()
如果不加鉤子就結束了,如果加鉤子繼續:
程式碼: form=UserForm(request.POST) 類的例項化:實際上是完成一次賦值, self.field={"user":user,'pwd':pwd,"email":email} 後面的值都是類例項化出來的物件,是各自的規則 user=forms.CharField(min_length=5, label="使用者名稱", error_messages=msg, widget=widgets.TextInput(attrs={"class":"form-control"}) ) pwd=forms.CharField(error_messages=msg, label="密碼", widget=widgets.PasswordInput(attrs={"class":"form-control"}) ) email=forms.EmailField(error_messages={"invalid":"郵箱格式錯誤"}, label="郵箱", widget=widgets.EmailInput(attrs={"class":"form-control"}) ) form.is_valid() self._clean_fields() #效驗欄位 #效驗資料 def _clean_fields(self): #field是各自的規則,name是欄位字串 for name, field in self.fields.items(): # value_from_datadict() gets the data from the data dictionaries. # Each widget type knows how to retrieve its own data, because some # widgets split data over several HTML fields. # UserForm({"user":"yuan",'pwd':123,'email':"123"}) if field.disabled: value = self.get_initial_for_field(field, name) else: # value就是 yuan 等 value = field.widget.value_from_datadict(self.data, self.files, self.add_prefix(name)) try: if isinstance(field, FileField): initial = self.get_initial_for_field(field, name) value = field.clean(value, initial) else: #field是校驗規則,value是 yuan 如果校驗不成功直接跳到except裡 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)
# 定義鉤子第一層校驗如果失敗了,區域性的鉤子就不執行了 def clean_user(self): val = self.cleaned_data.get('user') print(val) # user_obj = auth.authenticate(username=val) from django.contrib.auth.models import User user_obj=User.objects.filter(username=val).first() print("haha",user_obj) if user_obj: raise ValidationError('使用者名稱已存在') else: return val def clean_pwd(self): pwd = self.cleaned_data.get('pwd') if pwd.isdigit(): raise ValidationError('密碼是純數字') else: return pwd def clean_email(self): import re email = self.cleaned_data.get('email') if re.search('[0-9a-zA-Z][email protected]\.com', email): return email else: raise ValidationError('請輸入格式化為@163.com郵箱') # 全域性勾的錯誤的鍵為"__all___" def clean(self): pwd = self.cleaned_data.get("pwd") r_pwd = self.cleaned_data.get("r_pwd") print(r_pwd) if pwd and r_pwd: if pwd == r_pwd: return self.cleaned_data else: raise ValidationError('兩次密碼不一致!') else: return self.cleaned_data
可以給他起個別名,省著顯示錯誤資訊得時候還得判斷:
def clean(self): password = self.cleaned_data.get('password') r_pwd= self.cleaned_data.get('r_pwd') print(password,r_pwd) if password==r_pwd: print('haha') return self.cleaned_data else: self.add_error('r_pwd',ValidationError('密碼不一致'))