我想在管理員更改表單中製作一個完整的內聯表單集。因此,在我當前的情況下,當我點擊發票表單(在管理員)時,內聯訂單表單爲空。我想阻止人們創建沒有關聯訂單的發票。Django中的內聯表單驗證
任何人都知道一個簡單的方法來做到這一點?
模型字段上的正常驗證(例如(required=True
))在此實例中似乎不起作用。
我想在管理員更改表單中製作一個完整的內聯表單集。因此,在我當前的情況下,當我點擊發票表單(在管理員)時,內聯訂單表單爲空。我想阻止人們創建沒有關聯訂單的發票。Django中的內聯表單驗證
任何人都知道一個簡單的方法來做到這一點?
模型字段上的正常驗證(例如(required=True
))在此實例中似乎不起作用。
要做到這一點,最好的方法是定義一個自定義formset,並用一個乾淨的方法驗證至少存在一個發票順序。
class InvoiceOrderInlineFormset(forms.models.BaseInlineFormSet):
def clean(self):
# get forms that actually have valid data
count = 0
for form in self.forms:
try:
if form.cleaned_data:
count += 1
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count < 1:
raise forms.ValidationError('You must have at least one order')
class InvoiceOrderInline(admin.StackedInline):
formset = InvoiceOrderInlineFormset
class InvoiceAdmin(admin.ModelAdmin):
inlines = [InvoiceOrderInline]
丹尼爾的回答非常好,它爲我工作的一個項目,但後來我意識到,由於道路Django表單的工作,如果你正在使用can_delete,檢查刪除框,同時節省,這是可能的,以驗證W¯¯/o任何命令(在這種情況下)。
我花了一段時間試圖找出如何防止發生。第一種情況很簡單 - 不包括將在計數中被刪除的表格。第二種情況更棘手......如果全部刪除框被選中,則clean
未被調用。
不幸的是,代碼並不完全直截了當。從full_clean
調用clean
方法,當訪問error
屬性時調用該方法。刪除子窗體時不訪問此屬性,因此永遠不會調用full_clean
。我不是Django的專家,所以這可能是一個可怕的方式,但它似乎工作。
下面是修改後的類:
class InvoiceOrderInlineFormset(forms.models.BaseInlineFormSet):
def is_valid(self):
return super(InvoiceOrderInlineFormset, self).is_valid() and \
not any([bool(e) for e in self.errors])
def clean(self):
# get forms that actually have valid data
count = 0
for form in self.forms:
try:
if form.cleaned_data and not form.cleaned_data.get('DELETE', False):
count += 1
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count < 1:
raise forms.ValidationError('You must have at least one order')
class MandatoryInlineFormSet(BaseInlineFormSet):
def is_valid(self):
return super(MandatoryInlineFormSet, self).is_valid() and \
not any([bool(e) for e in self.errors])
def clean(self):
# get forms that actually have valid data
count = 0
for form in self.forms:
try:
if form.cleaned_data and not form.cleaned_data.get('DELETE', False):
count += 1
except AttributeError:
# annoyingly, if a subform is invalid Django explicity raises
# an AttributeError for cleaned_data
pass
if count < 1:
raise forms.ValidationError('You must have at least one of these.')
class MandatoryTabularInline(admin.TabularInline):
formset = MandatoryInlineFormSet
class MandatoryStackedInline(admin.StackedInline):
formset = MandatoryInlineFormSet
class CommentInlineFormSet(MandatoryInlineFormSet):
def clean_rating(self,form):
"""
rating must be 0..5 by .5 increments
"""
rating = float(form.cleaned_data['rating'])
if rating < 0 or rating > 5:
raise ValidationError("rating must be between 0-5")
if (rating/0.5) != int(rating/0.5):
raise ValidationError("rating must have .0 or .5 decimal")
def clean(self):
super(CommentInlineFormSet, self).clean()
for form in self.forms:
self.clean_rating(form)
class CommentInline(MandatoryTabularInline):
formset = CommentInlineFormSet
model = Comment
extra = 1
@Daniel羅斯曼的解決方案是好的,但我有一些較少的代碼做一些修改,以做到這一點相同。
試試這個它也可以:)
完美解決方案,謝謝 – user108791 2009-05-18 15:01:41
我發現,如果刪除複選框被選中,這是可能的0訂單來驗證。查看我的答案,找到解決該問題的修訂課程。 – 2009-12-10 23:13:47
非常感謝您爲此解決方案(和丹增強)。 作爲一個可能的提示給別人,我做了一個'類MandatoryInlineFormSet(BaseInlineFormSet)',然後從中派生了InvoiceAdminFormSet。在我的InvoiceAdminFormSet中,我有一個用於自定義驗證的clean()方法,但首先調用MandatoryInlineFromSet.clean()。 – Kurt 2010-06-03 15:19:45