2012-04-27 7 views
7

ここではかなり基本的な使用例があります。オブジェクトを作成したユーザーと最後に変更したユーザーを保存します。しかし、インラインモデルなので、もちろんsave_formsetを使用する必要があります。 Djangoのドキュメントは、以下の例のコードを持っている:あなたが気づいた場合ModelAdminでsave_formsetをさらにオーバーライドできるようにする

class ArticleAdmin(admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for instance in instances: 
      instance.user = request.user 
      instance.save() 
     formset.save_m2m() 

事が呼び出されることはありませんsuperいるので、これはデッドエンドである、です。 ModelAdminがサブクラス化されていて、このメソッドが同じ方法でオーバーライドされると、親に固有の機能が失われます。これは私が機能性を考慮したい、そのような一般的な使用シナリオですので、私は次のように作成したので、これは重要:

class TrackableInlineAdminMixin(admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for instance in instances: 
      if hasattr(instance, 'created_by') and hasattr(instance, 'modified_by'): 
       if not instance.pk: 
        instance.created_by = request.user 
       instance.modified_by = request.user 
      instance.save() 
     formset.save_m2m() 
     super(TrackableInlineAdminMixin, self).save_formset(request, form, formset, change) 

私がいることを考えていない、何よりも習慣のうち、superへの呼び出しにタック実際には、フォームセットは2回保存されます。それにもかかわらず、1つを除いてすべてのシナリオで動作します:削除。管理者のインラインを削除しようとすると、エラーが発生します。エラーは非常にあいまいであり、ここで私の質問に実際には反応しませんが、インスタンスセットの1つを削除した後にformsetを再度保存しようとするのと関連していると思います。コードはsuperへの呼び出しが削除されたときに正常に機能します。

長すぎると短く、フォームセットの保存動作をカスタマイズする方法がありませんサブクラスで独自のオーバーライドを実行できますか?

+2

でDjangoの1.10を使用して、また削除の問題の世話をするように見えるコード、であるだけで[未解決チケット](https://code.djangoproject.com/ましたチケット/ 17988) – okm

答えて

5

これはドギーです。

私は楽しんでいましたが、これはすべてdjango.forms.models.BaseModelFormSetで起こったようです。 はcommitフラグに関係なくインスタンスを削除し、削除された状態を反映するようにフォームを変更しないという問題があります。

save()を再度呼び出すと、フォーム上を反復処理され、ModelChoiceFieldクリーニングでは、参照されたIDをプルして無効な選択エラーがスローされます。

​​

私はこの問題を解決することができた唯一の方法は、オブジェクトが削除される場合self.formsからフォームを削除するBaseModelFormset.save_existing_objectsにパッチを適用することです。

いくつかのテストを行っても、悪影響はないようです。

+0

徹底的な分析をお寄せいただきありがとうございます。私はちょうど何かが完全に欠落していないことを確認するためにサニティチェックをしたかったのですが、パッチがDjangoソースに必要な場合、これはバグレポートの主要な候補のようです。 –

0

@クリス・プラットは助け:

を私は が、それは実際にフォームセットは、二回保存するようになりますことを考えていない、何よりも習慣のうち、スーパーへの呼び出しにタック。

ポストセーブ信号を送信するために、save_formsetをさらに上書きしようとしていました。私はちょうどsuper()を呼び出すことが2回目のformsetを保存していたことを理解できませんでした。

super()問題に対処するために、私は私がadmin.ModelAdmin子供を通じてsave_formsetを上書きするとき、私は呼んでいることを、私のカスタムコードでsave_formset_nowメソッドを作成しました。

は、これは2016年

class BaseMixinAdmin(object): 
    def save_formset_now(self, request, form, formset, change): 
     instances = formset.save(commit=False) 
     for obj in formset.deleted_objects: 
      obj.delete() 
     for instance in instances: 
      # *** Start Coding for Custom Needs *** 
       .... 
      # *** End Coding for Custom Needs *** 
      instance.save() 
     formset.save_m2m() 

class BaseAdmin(BaseMixinAdmin, admin.ModelAdmin): 
    def save_formset(self, request, form, formset, change): 
     self.save_formset_now(request, form, formset, change) 


class ChildAdmin(BaseAdmin): 
    def save_formset(self, request, form, formset, change): 
     self.save_formset_now(request, form, formset, change) 
     my_signal.send(...) 
関連する問題