post_save
モデルを (管理者経由で) 保存したときに更新されない多対多の関係に問題があり、信号に添付された関数内またはsave_model
関連付けられた 内で新しい値を使用しようとしましたAdminModel
。get 関数と id.. を使用して、これらの関数内でオブジェクトをリロードしようとしましたが、まだ古い値が残っています。
これはトランザクションの問題ですか?トランザクションが終了したときにシグナルがスローされますか?
ありがとう、
post_save
モデルを (管理者経由で) 保存したときに更新されない多対多の関係に問題があり、信号に添付された関数内またはsave_model
関連付けられた 内で新しい値を使用しようとしましたAdminModel
。get 関数と id.. を使用して、これらの関数内でオブジェクトをリロードしようとしましたが、まだ古い値が残っています。
これはトランザクションの問題ですか?トランザクションが終了したときにシグナルがスローされますか?
ありがとう、
管理フォームを介してモデルを保存する場合、それはアトミック トランザクションではありません。最初にメイン オブジェクトが保存され (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を投稿しました。試したことはありませんが、うまくいくようです。
モデルの post_save シグナルで ManyToMany フィールドにアクセスしようとすると、関連するオブジェクトは既に削除されており、シグナルが終了するまで再び追加されません。
このデータにアクセスするには、ModelAdmin の save_related メソッドに関連付ける必要があります。残念ながら、カスタマイズが必要な管理者以外のリクエストの post_save シグナルにもコードを含める必要があります。
例:
# 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: []
これに対する一般的な解決策は、コアにモンキーパッチを適用したり、セロリを使用したりするよりも少しきれいに思えます (ただし、誰かが失敗する領域を見つけることができると確信しています)。基本的に、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])
このスレッドで詳細情報を見つけることができます: Django manytomany signal?