Django多对多关系插入控件

时间:2013-05-24 08:41:15

标签: django django-signals django-models

我有以下型号:

class Item(models.Model):
    # fields
    # ...

class Collection(models.Model):
    items = models.ManyToManyField(Item, related_name="collections")
    # other fields
    # ...

现在我想要两件事:

  1. 我想控制是否可以将Item添加到Collection
  2. 如果添加或删除Collection,我希望Item更新其中的某些字段。
  3. 对于第二个问题,我知道有django.db.models.signals.m2m_changed可以用来挂钩关系的变化。允许/确定更改信号回调中的Collection吗?我是否也可以使用该信号“中止”问题1的插入?

2 个答案:

答案 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)

  1. 在保存实例之前调用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
    
  2. 将实例添加到m2m字段时,不会调用save方法。你是对的,m2m_changed信号是要走的路。您可以安全地更新那里的集合实例。