我想在管理员更改表单中制作一个完整的内联表单集。因此,在我当前的情况下,当我点击发票表单(在管理员)时,内联订单表单为空。我想阻止人们创建没有关联订单的发票。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