6

我有以下型号:

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

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

现在我想要两件事:

  1. 我想控制是否Item可以将 a 添加到Collection.
  2. 如果添加或删除了,我希望Collection更新它的一些字段。Item

对于第二个问题,我知道django.db.models.signals.m2m_changed我可以使用它来挂钩关系的变化。Collection是否允许/可以在信号回调中更改?我可以使用该信号来“中止”问题 1 的插入吗?

4

2 回答 2

8

我认为处理您想要的两种行为的最佳方法不是使用信号,而是使用through表上覆盖的 save() 和 delete() 方法,您将使用参数明确定义,through请参见: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

像这样的东西:

# -*- coding: utf-8 -*-

from django.db import models


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

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

class CollectionItem(models.Model):
    collection = models.ForeignKey(Collection)
    item = models.ForeignKey(Item)

    def save(self, *args, **kwargs):
        # Only allow this relationship to be created on some_condition
        # Part 1 of your question.
        if some_condition:
            super(CollectionItem, self).save(*args, **kwargs)

            # Update some fields on Collection when this
            # relationship is created
            # Part 2 of your question (1/2)
            self.Collection.updateSomeFields()

    def delete(self, *args, **kwargs):
        collection = self.collection
        super(CollectionItem, self).delete(*args, **kwargs)

        # Update some fields on Collection when this relationship
        # is destroyed.
        # Part 2 of your question (2/2)
        collection.updateSomeFields()

顺便说一句,您会发现添加关系在此直通模型上引起保存信号。

而且,关于信号,一旦你有了直通表,你就可以收听 pre_save 和/或 post_save 信号,但它们都不允许你直接否决关系的创建。

如果您的一个或两个模型是由第 3 方提供的,并且您确实无法创建直通表,那么,是的,信号路径可能是唯一的方法。

https://docs.djangoproject.com/en/dev/ref/signals/#m2m-changed

在这种情况下,您可以侦听 m2m_changed 事件并触发对您的集合对象的更新(您的问题的第 2 部分)并追溯删除不当创建的关系(您的问题的第 1 部分)。但是,由于后一点很笨拙,如果可以的话,我会坚持使用显式直通表。

于 2013-05-28T19:13:54.473 回答
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信号就是要走的路。您可以在那里安全地更新集合实例。

于 2013-05-28T14:14:44.593 回答