57

管理者変更フォーム内のインライン フォームセット全体を必須にしたいと考えています。そのため、現在のシナリオでは、(管理者の) 請求書フォームで保存を押すと、インラインの注文フォームが空白になります。注文が関連付けられていない請求書を作成する人を止めたいです。

誰でもそれを行う簡単な方法を知っていますか?

モデル フィールドの( ) のような通常の検証required=Trueは、このインスタンスでは機能しないようです。

4

5 に答える 5

85

これを行う最善の方法は、少なくとも 1 つの請求書注文が存在することを検証するクリーンなメソッドを使用して、カスタム フォームセットを定義することです。

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]
于 2009-05-18T14:06:07.777 に答える
22

ダニエルの答えは素晴らしく、あるプロジェクトではうまくいきましたが、Django フォームの仕組みにより、can_delete を使用して保存中に削除ボックスをチェックすると、注文なしで検証できることに気付きました (この中で場合)。

私はそれが起こらないようにする方法を見つけようとしてしばらく時間を費やしました. 最初の状況は簡単でした。削除されるフォームをカウントに含めないでください。2 番目の状況はよりトリッキーでした...すべての削除ボックスがチェックされている場合clean、呼び出されませんでした。

残念ながら、コードは単純ではありません。cleanメソッドは、プロパティがアクセスされたときに呼び出されるから呼び出されますfull_cleanerrorこのプロパティは、サブフォームが削除されているときはアクセスされないため、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')
于 2009-12-10T23:11:20.637 に答える
4
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  
于 2010-06-03T15:21:44.103 に答える
4

@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]

これも機能します:)

于 2011-07-20T15:04:55.140 に答える