2009-05-18 13 views
41

管理変更フォーム内のインラインフォームセット全体を強制的に作成したいと考えています。私の現在のシナリオでは、インボイスフォーム(管理者)の保存を押すと、インラインオーダーフォームは空白になります。私は、注文を伴わない請求書の作成を止めたいと思っています。Djangoのインラインフォーム検証

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

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

答えて

63

少なくとも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] 
+0

完璧なソリューションをこれを試してみてください、ありがとう – user108791

+3

私は削除ボックスがチェックされている場合、それは0注文で検証することも可能だということが分かりました。その問題を解決する改訂されたクラスの私の答えを参照してください。 –

+0

この修正プログラム(および強化のためのDan)に感謝します。 私は 'MandatoryInlineFormSet(BaseInlineFormSet)'クラスを作成し、それからInvoiceAdminFormSetを導き出しました。 InvoiceAdminFormSetには、カスタム検証を行うclean()メソッドがありますが、最初にMandatoryInlineFromSet.clean()にコールバックします。 – Kurt

18

ダニエルの答えは優れており、それは一つのプロジェクトに私のために働いたが、その後、私は原因Djangoは仕事を形成する方法に実現し、あなたがcan_deleteを使用し、節約しながら削除]チェックボックスをオンにしている場合、それはワットを検証することが可能です/ o任意の注文(この場合)。

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

コードは、残念ながら、まったく簡単なものではありません。 cleanメソッドは、errorプロパティにアクセスするときに呼び出されるfull_cleanから呼び出されます。このプロパティは、サブフォームが削除されているときにはアクセスされないため、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') 
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 
+0

で働くことです余分な= 0で同じことをすることが可能ですか? –

+1

@シヴァ - 私はちょうどチェックした、そして余分な= 0を持つことができます。しかし、コメントを(私の場合は)必須にするには、ユーザーに空白のフォームを指定するか、必須にしないでください。 – Kurt

4

@Danielローズマン液が細かいですが、私はこの同じことを行うには、いくつかのより少ないコードでいくつかの変更があります。

​​

それも動作します:)

+0

うわー、これをアップフォートするつもりはありませんでした。 「削除」チェックボックスをオンにしても機能しません。 – Tobu

+0

あなたの質問を理解できませんでしたか?このコードでは、すべての 'Invoice'に1つの' InvoiceOrder'がなければなりません。その時、削除チェックボックスはありません! – Ahsan

関連する問題