2011-08-07 21 views
4

私は2多対多フィールドを持つDjangoモデルを持っています。モデルが管理インターフェースから保存されるとき、私は第2フィールドが空白であるかどうかをチェックする必要があり、それが空白であれば、第1フィールドから第2フィールドにコピーされたアイテムが必要です。これどうやってするの?それは素晴らしい仕事だろうが、私は、フィールドをコピーした後、私はインスタンスを保存するために得ることができないようDjangoの多対多フィールドコピー

UPDATE

マシューの答えはそうです。私は何も成功せずにinstance.save()を試してみました。

+1

...オブジェクトを保存し、第二M2Mから関連データを取得し、最初のM2Mに設定して、もう一度それを保存します。 instance.save()ラインを押し、「s」は関数を入力し、で、何が起こっているかを確認するために直前pdb.set_trace()「N」あなたは次に行き。ここでは、[チュートリアル](http://pythonconquerstheuniverse.wordpress.com/category/python-debugger/)は念 – Hassek

答えて

3

post_saveではなく、m2m_changedの信号が、モデルがデータベースに保存された後に送信されます。

@models.signals.m2m_changed(sender=MyModel.second_m2m.through) 
def duplicate_other_on_this_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs): 
    # just before adding a possibly empty set in "second_m2m", check and populate. 
    if action == 'pre_add' and not pk_set: 
     instance.__was_empty = True 
     pk_set.update(instance.first_m2m.values_list('pk', flat=True)) 

@models.signals.m2m_changed(sender=MyModel.first_m2m.through) 
def duplicate_this_on_other_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs): 
    # Just in case the "first_m2m" signals are sent after the other 
    # so the actual "population" of the "second_m2m" is wrong: 
    if action == 'post_add' and not pk_set and getattr(instance, '__was_empty'): 
     instance.second_m2m = list(pk_set) 
     delattr(instance, '__was_empty') 

編集:次のコードは単純であり、そして、あなたのコードでモデルの定義

に新しい知識に基づいて「first_m2m」信号「がsecond_m2m」の前に送信されます(それは実際に依存あなたのモデル定義)。したがって、「second_m2m」信号が受信されると、「first_m2m」にはすでに現在のデータが入力されているという前提で作業できます。今、あなたが唯一のM2M-事前加算をチェックする必要があるため

これは、私たちが幸せになります:

@models.signals.m2m_changed(sender=MyModel.second_m2m.through) 
def duplicate_other_on_this_if_empty(sender, instance, action, reverse, model, pk_set, **kwargs): 
    # just before adding a possibly empty set in "second_m2m", check and populate. 
    if action == 'pre_add' and not pk_set: 
     pk_set.update(instance.first_m2m.values_list('pk', flat=True)) 
+0

https://docs.djangoproject.com/en/dev/ref/signals/#django.db.models.signals.m2m_changedによると、 'before_add'と 'after_add'はありません。あなたは 'pre_add'と 'post_add'を意味しますか? –

+1

はい、もちろんです。申し訳ありませんが私はそれを修正します。 (より複雑なバージョン)これは私が現在m2mの内容が常に別のもののサブセットであることを確実にするために使用している方法です(そうしないと有効にしなければならない "有効"と "有効" – rewritten

+0

それは私のために働いていないと私は理由を把握することはできません。私はいくつかのログを印刷していますが、missing_field_2がmissing_field_1の前に実行されていることに気付いています。次に、__was_emptyが定義されていないというエラーをスローします。何か案は? –

0

あなたは余分な検証を行うためにきれいなメソッドをオーバーライドすることができますので、二many2manyが空白の場合は、例えば、デフォルト値を設定することができます:あなたは内部models.pyの中で、あなたがこのコードを設定すべきである

def clean(self): 
    super(MyClassModel, self).clean() 

    if not self.MySecondMany2Many: 
     # fill data 

あなたのクラス。モデルを保存する必要があるためクリーンが機能しない場合は、保存関数をオーバーライドすることもできますが、これは同じ手順です。

私はそれをテストhaventは、私はmany2manyフィールドがそのように空白であるかどうかをチェックすることができないと思いますが、あなたのアイデアを得る必要があります:)

+0

うーんです。保存する前にm2mフィールドを使って処理することは、大きな方法で消滅する可能性があります。つまり、PKMが存在する前にPKを使用しようとします。 –

+0

あなたはより良い保存を無効にすることができます。しかし、今マシューはpost_save信号について投稿していること、私はそれが問題にクリーンな解決策であることに同意します。 – Hassek

3

あなたはポストセーブ信号を使用することができます。これはあなたのニーズをここで処理する最善の方法かもしれないようです:ボーナスは管理者の外でも機能するということです。

@models.signals.post_save(sender=MyModel) 
def duplicate_missing_field(sender, instance, **kwargs): 
    if not instance.my_second_m2m.count(): 
     instance.my_second_m2m.add(*instance.my_first_m2m.all()) 
     # or *instance.my_first_m2m.values_list('pk', flat=True), I think 

私のコードは正しいとは限りません。あなたはdjangoのシグナルを読みたいと思うでしょう。

+0

は素晴らしい解決策のように思えるが、私は値を追加した後に保存するインスタンスを取得することはできません。私はinstance.save()を試みたが、それは動作しません。何か案は? –

+0

保存後にpost_save信号が送信されますが、m2mの挿入キューはすでに完了していますので、そこで変更することはできません。代わりにm2m_changedを使用してください。 – rewritten

0

あなたがあれば、それをオーバーライドして、関連するフィールドが空であるかどうかを確認、ここからadmin save overrideの定義を見ることができますそう、私は通常、輸入PDBを配置しよう、何が起こっているかをチェックするために、PythonのPDBでデバッグ