Form中添加自定義的驗證:
???1.對特定字段屬性的驗證;
???2.包含多字段的驗證.
先創(chuàng)建一個簡單的Form:
from django import forms
class ContactForm(forms.Form):
subject = forms.CharField(max_length=100)
message = forms.CharField()
sender = forms.EmailField()
recipients = MultiEmailField()
cc_myself = forms.BooleanField(required=False)
1.驗證特定字段屬性
使用表單子類中的clean_<fieldname>()
方法 -- <fieldname>通過表單中的字段名稱替換.這個方法完成特定屬性相關的驗證,這個驗證與字段的類型無關.這個方法沒有任何傳入的參數(shù).你需要查找self.cleaned_data
中該字段的值,記住此時它已經(jīng)是一個python對象而不是表單中提交的原始字符串(它位于cleaned_data
中是因為字段的clean()
方法已經(jīng)驗證過一次數(shù)據(jù)).
例如,在ContactForm
中,我們想確保recipients
字段始終包含'fred@example.com'.這是特定于我們這個表單的驗證,所以我們打算將它放在通用的MultiEmailField
類中.編寫一個運行在recipients
字段上的驗證方法:
from django import forms
class ContactForm(forms.Form):
#Everything as before
...
def clean_recipients(self):
data = self.cleaned_data['recipients']
if 'fred@example.com' not in data:
raise forms.ValidationError('You havev forgotten Fred!')
# Always return a value to use as the new cleaned data, even if this method didn't change it
return data
2.驗證相互依賴的字段
假設我們添加另外一個需求到聯(lián)系人表單中:如果cc_myself
字段為True
,那么subject
必須包含單詞'help'.這個驗證包含多個字段,所以表單的clean()
方法是個不錯的地方.
注意,這里討論的是表單的clean()
方法,上面有提到一個字段的clean()
方法.區(qū)別字段和表單之間的差別非常重要,字段是單個數(shù)據(jù),表單是字段的集合.
在調(diào)用表單clean()
方法的時候,所有字段的驗證方法已經(jīng)執(zhí)行完,所以self.cleaned_data
填充的是目前為止已經(jīng)合法的數(shù)據(jù).所以需要記住一個事實,你需要驗證的字段可能沒有通過初始的字段檢查!
from django import forms
class ContactForm(forms.Form):
# Everything as before
...
def clean(self):
cleaned_data = super(ContactForm, self).clean()
cc_myself = cleaned_data.get('cc_myself')
subject = cleaned_data.get('subject')
if cc_myself and subject:
# Only do something if both fields are valid so far.
if 'help' not in subject:
raise forms.ValidationError("Did not send for 'help' in the subject despite CC'ing yourself")
在這段代碼中贱枣,如果拋出驗證錯誤抖锥,表單將在表單的頂部顯示(通常是)描述該問題的一個錯誤信息浊吏。
注意子房,示例代碼中super(ContactForm, self).clean()
的調(diào)用是為了保證維持父類中的驗證邏輯巩螃。
3.多表單提交的外鍵處理
假設有多個模型之間存在外鍵關系,那么在同一個頁面同時提交這幾個表單的處理方法:
建立幾個模型:
from django.db import models
class Store(models.Model):
...
class Deport(models.Model):
s_name = models.ForeignKey(Store)
...
class Address(models.Model):
s_name = models.ForeignKey(Store)
...
給這幾個模型分別建立模型表單.
由于其中兩個表使用了1個外鍵約束,如果同時提交和保存數(shù)據(jù)會導致數(shù)據(jù)表中的s_name_id
字段值為NULL
.為了解決這個問題,我們采用延遲提交給數(shù)據(jù)庫的方式.
ModelForm的save()方法接受一個可選的commit
關鍵字參數(shù),其值為True/False
.如果save()
時commit=False
,那么它將返回一個還沒保存到數(shù)據(jù)庫的模型實例對象.這種情況下,你需要調(diào)用該返回的模型實例的save()
方法.這樣你可以在保存數(shù)據(jù)之前進行一些自定義的處理.commit
默認為True
.
from django.views.generic.base import View
class Store_Add(View):
...
def post(self, request):
sf = StoreForm(request.POST)
df = DeportForm(request.POST)
af = AddressForm(request.POST)
if sf.is_valid() and df.is_valid() and af.is_valid():
store = sf.save()
dform = df.save(commit=False) # 將來自DeportForm的數(shù)據(jù)暫存為一個模型實例,其中s_name字段為空
dform.s_name = store
dform.save()
aform = af.save(commit=False)
aform.s_name = store
aform.save()
...
4.從表單中訪問字段
可以通過表單的fields
屬性訪問字段:
#models.py
from django.db import models
class Publisher(models.Model):
name = models.CharField(max_length=30)
address = models.CharField(max_length=50)
website = models.URLField()
def __str__(self):
return self.name
#forms.py
from django import forms
from myapp.models import Publisher
class PublisherForm(forms.ModelForm):
class Meta:
model = Publisher
fields = '__all__'
>>> form = PublisherForm()
>>> form.fields
# 返回一個有序字典對象,鍵為Form中的字段名,值為fields對象
OrderedDict([('name', <django.forms.fields.CharField at 0x1d075ebca90>),
('address', <django.forms.fields.CharField at 0x1d075ebcb38>),
('website', <django.forms.fields.URLField at 0x1d07696cc18>)])
可以使用字典的方法對Form的字段進行一些操作,例如:
form.fields.update({'website': forms.CharField(widget=forms.TextInput()})
后者動態(tài)的對某一個字段的屬性進行修改:
form.fields['website'].initial = self.request.user.website
fields對象的一些參數(shù)(屬性)參考文檔中的說明.
參考:http://python.usyiyi.cn/translate/django_182/ref/forms/validation.html#validating-fields-with-clean
???https://segmentfault.com/a/1190000007183873