保存后不立即更新多对多关系的问题

问题描述:

我遇到了未更新的多对多关系问题在我保存模型时(通过管理员)并尝试在一个模型中使用新值附加到 post_save 信号或在 save_model 中的函数关联的 AdminModel.我试图通过使用在这些函数中重新加载对象获取带有 id 的函数......但它仍然具有旧值.

I'm having issues with ManytoMany Relationships that are not updating in a model when I save it (via the admin) and try to use the new value within a function attached to the post_save signal or within the save_model of the associated AdminModel. I've tried to reload the object within those functions by using the get function with the id.. but it still has the old values.

这是交易问题吗?是否有信号抛出时交易结束?

Is this a transaction issue? Is there a signal thrown when the transaction ends?

谢谢,

当您通过管理表单保存模型时,它不是原子事务.主要对象首先被保存(以确保它有一个 PK),然后 M2M 被清除,并将新值设置为表单中的任何内容.因此,如果您在主对象的 save() 中,您就处于 M2M 尚未更新的机会窗口中.事实上,如果您尝试对 M2M 做一些事情,那么更改将被 clear() 清除.大约一年前我遇到了这个问题.

When you save a model via admin forms it's not an atomic transaction. The main object gets saved first (to make sure it has a PK), then the M2M is cleared and the new values set to whatever came out of the form. So if you are in the save() of the main object you are in a window of opportunity where the M2M hasn't been updated yet. In fact, if you try to do something to the M2M, the change will get wiped out by the clear(). I ran into this about a year ago.

代码与 ORM 重构前的时代相比有所改变,但归结为 django.db.models.fields.ManyRelatedObjectsDescriptorReverseManyRelatedObjectsDescriptor 中的代码.看看他们的 __set__() 方法,你会看到 manager.clear();manager.add(*value) clear() 完成清除该表中当前主要对象的任何 M2M 引用.然后 add() 设置新值.

The code has changed somewhat from the pre-ORM refactor days, but it boils down to code in django.db.models.fields.ManyRelatedObjectsDescriptor and ReverseManyRelatedObjectsDescriptor. Look at their __set__() methods and you'll see manager.clear(); manager.add(*value) That clear() complete cleans out any M2M references for the current main object in that table. The add() then sets the new values.

所以回答你的问题:是的,这是一个交易问题.

So to answer your question: yes, this is a transaction issue.

事务结束时是否有抛出信号?不是官方的,但请继续阅读:

Is there a signal thrown when the transaction ends? Nothing official, but read on:

几个月前有一个相关主题和 MonkeyPatching是提出的一种方法.Grégoire 为此发布了一个 MonkeyPatch.我没试过,但看起来应该可以.

There was a related thread a few months ago and MonkeyPatching was one method proposed. Grégoire posted a MonkeyPatch for this. I haven't tried it, but it looks like it should work.