25

post_saveモデルを (管理者経由で) 保存したときに更新されない多対多の関係に問題があり、信号に添付された関数内またはsave_model関連付けられた 内で新しい値を使用しようとしましたAdminModel。get 関数と id.. を使用して、これらの関数内でオブジェクトをリロードしようとしましたが、まだ古い値が残っています。

これはトランザクションの問題ですか?トランザクションが終了したときにシグナルがスローされますか?

ありがとう、

4

6 に答える 6

33

管理フォームを介してモデルを保存する場合、それはアトミック トランザクションではありません。最初にメイン オブジェクトが保存され (PK があることを確認するため)、次に M2M がクリアされ、新しい値がフォームから出てきたものに設定されます。そのため、メイン オブジェクトの save() にいる場合は、M2M がまだ更新されていない機会のウィンドウにいます。実際、M2M に何かをしようとすると、変更は clear() によって消去されます。私は約1年前にこれに出くわしました。

コードは、ORM リファクタリング前の時代から多少変更されていますが、要約すると と のコードにdjango.db.models.fields.ManyRelatedObjectsDescriptorなりReverseManyRelatedObjectsDescriptorます。それらの __set__() メソッドを見ると、manager.clear(); manager.add(*value)clear() が完全にそのテーブル内の現在のメイン オブジェクトの M2M 参照を一掃していることがわかります。次に add() が新しい値を設定します。

あなたの質問に答えるには: はい、これはトランザクションの問題です。

トランザクションが終了したときにシグナルがスローされますか? 公式なものは何もありませんが、読んでください:

数か月前に関連するスレッドがあり、MonkeyPatching は提案された 1 つの方法でした。Grégoire はこれについて MonkeyPatchを投稿しました。試したことはありませんが、うまくいくようです。

于 2009-12-18T01:41:13.753 に答える
9

モデルの post_save シグナルで ManyToMany フィールドにアクセスしようとすると、関連するオブジェクトは既に削除されており、シグナルが終了するまで再び追加されません。

このデータにアクセスするには、ModelAdmin の save_related メソッドに関連付ける必要があります。残念ながら、カスタマイズが必要な管理者以外のリクエストの post_save シグナルにもコードを含める必要があります。

参照: https://docs.djangoproject.com/en/1.7/ref/contrib/admin/#django.contrib.admin.ModelAdmin.save_related

例:

# admin.py
Class GroupAdmin(admin.ModelAdmin):
    ...
    def save_related(self, request, form, formsets, change):
        super(GroupAdmin, self).save_related(request, form, formsets, change)
        # do something with the manytomany data from the admin
        form.instance.users.add(some_user)

次に、シグナルで、保存時に実行したいのと同じ変更を加えることができます。

# signals.py
@receiver(post_save, sender=Group)
def group_post_save(sender, instance, created, **kwargs):
    # do somethign with the manytomany data from non-admin
    instance.users.add(some_user)
    # note that instance.users.all() will be empty from the admin: []
于 2015-02-11T23:41:06.523 に答える
5

これに対する一般的な解決策は、コアにモンキーパッチを適用したり、セロリを使用したりするよりも少しきれいに思えます (ただし、誰かが失敗する領域を見つけることができると確信しています)。基本的に、m2m リレーションシップを持つフォームの admin に clean() メソッドを追加し、インスタンス リレーションをcleaned_data バージョンに設定します。これにより、インスタンスの save メソッドで正しいデータを利用できるようになります。試してみて、どうなるか見てみましょう:

def clean(self, *args, **kwargs):
    # ... actual cleaning here
    # then find the m2m fields and copy from cleaned_data to the instance
    for f in self.instance._meta.get_all_field_names():
        if f in self.cleaned_data:
            field = self.instance._meta.get_field_by_name(f)[0]
            if isinstance(field, ManyToManyField):
                setattr(self.instance,f,self.cleaned_data[f])
于 2011-08-09T18:12:42.003 に答える
0

このスレッドで詳細情報を見つけることができます: Django manytomany signal?

于 2011-05-18T16:06:50.690 に答える