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]
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')
1
@Daniel Roseman解决方案很好,但是我做了一些修改,只用了一些代码来做同样的事情 .
class RequiredFormSet(forms.models.BaseInlineFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
self.forms[0].empty_permitted = False
class InvoiceOrderInline(admin.StackedInline):
model = InvoiceOrder
formset = RequiredFormSet
class InvoiceAdmin(admin.ModelAdmin):
inlines = [InvoiceOrderInline]
试试这个它也有效:)
2
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
5 回答
执行此操作的最佳方法是使用clean方法定义自定义formset,该方法验证至少存在一个发票订单 .
Daniel的答案非常好,它在一个项目上对我有用,但后来我意识到由于Django的工作方式,如果你使用can_delete并在保存时检查删除框,则可以验证没有任何订单(在此案件) .
我花了一些时间试图弄清楚如何防止这种情况发生 . 第一种情况很简单 - 不包括将在计数中删除的表单 . 第二种情况比较棘手......如果检查了所有删除框,则没有调用
clean
.遗憾的是,代码并不简单 . 从
full_clean
调用clean
方法,该方法在访问error
属性时调用 . 删除子表单时不会访问此属性,因此永远不会调用full_clean
. 我不是Django的专家,所以这可能是一种可怕的方式,但似乎有效 .这是修改后的类:
@Daniel Roseman解决方案很好,但是我做了一些修改,只用了一些代码来做同样的事情 .
试试这个它也有效:)
我们在2018年有很多很棒的新闻!唐纳德特朗普今天是美国的坚持者,我们仍在努力解决所需的内联问题 .
情况变得更好但仍需要一些解决方法 . Django现在提供
validate_min
和min_num
attrs,如果min_num
取自Inline
durring formset instantinating,validate_min
只能作为init formset参数传递 . 所以解决方案看起来像这样: