我有以下型号:
class Item(models.Model):
# fields
# ...
class Collection(models.Model):
items = models.ManyToManyField(Item, related_name="collections")
# other fields
# ...
现在我想要两件事:
Item
添加到Collection
。Collection
,我希望Item
更新其中的某些字段。对于第二个问题,我知道有django.db.models.signals.m2m_changed
可以用来挂钩关系的变化。允许/确定更改信号回调中的Collection
吗?我是否也可以使用该信号“中止”问题1的插入?
答案 0 :(得分:8)
我认为处理所需行为的最佳方法不是使用信号,而是使用through
表上的重写的save()和delete()方法,您将使用参数{显式定义} {1}}见https://docs.djangoproject.com/en/dev/ref/models/fields/#django.db.models.ManyToManyField.through。而这:https://docs.djangoproject.com/en/dev/topics/db/models/#overriding-predefined-model-methods
这样的事情:
through
顺便提一下,您会发现添加关系将在此模型中产生保存信号。
而且,关于信号,一旦你有了直通表,你就能听到pre_save和/或post_save信号,但是它们都不会让你直接否决关系的创建。
如果您的一个或两个模型由第三方提供,而您实际上无法创建直通表,那么,是的,信号路线可能是唯一的方法。
https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed
在这种情况下,您可以侦听m2m_changed事件并触发对集合对象的更新(问题的第2部分),并追溯删除不恰当创建的关系(问题的第1部分)。然而,由于后一位是一个非常丑陋的kludgy,如果可以,我会坚持使用显式通过表。
答案 1 :(得分:3)
在保存实例之前调用pre_save
信号。但是你无法从那里中止保存操作。更好的解决方案是向Collection
模型添加新方法,该方法负责检查是否可以添加Item
:
class Collection(models.Model):
items = models.ManyToManyField(Item, related_name="collections")
...
def add_item(self, item):
if check_if_item_can_be_added(item):
items.add(item)
self.save()
def check_if_item_can_be_added(self, item):
# do your checks here
将实例添加到m2m字段时,不会调用save方法。你是对的,m2m_changed
信号是要走的路。您可以安全地更新那里的集合实例。