在Django的save方法中动态添加多对多关系

时间:2016-08-22 15:31:34

标签: django django-models many-to-many django-orm

我的内容模型与Tag模型有多对多的关系。当我保存Content对象时,我想动态添加关系。我这样做的方式如下。

# models.py   

def tag_content(content_id):
    obj = Content.objects.get(pk=content_id)
    print obj # Checking
    obj.tags = [1, 2, 3] # Adding the relationships using the Tag IDs

class Tag(models.Model):
    name = models.CharField(max_length=255)

class Content(models.Model):
    title = models.CharField(max_length=255)
    is_tagged = models.BooleanField(default=False)
    tags = models.ManyToManyField(Tag, blank=True)

    def save(self, *args, **kwargs):
        super(Content, self).save(*args, **kwargs)
        if not self.is_tagged:
            tag_content(self.pk) # calling the tagging method

换句话说,当保存Content对象时,其tags对象与3个不同的Tag对象模型相关。只是为了让你知道,我确实在数据库中有pks = 1,2和3的标签。

但是,这根本不起作用。 save方法调用tag_content方法,因为print obj语句有效。但是,多对多字段未设置并保持为空。有趣的是,如果我在shell中运行以下命令,则标记字段设置完美。

# python manage.py shell
from myapp.models import *
obj = Content.objects.get(pk=1)
tag_content(obj.pk)

那么shell版本是如何工作的,但是另一个版本没有?任何帮助表示赞赏。

1 个答案:

答案 0 :(得分:3)

由于Django将这些关系写入数据库的方式,您无法在自定义save方法中处理m2m关系。当保存具有m2m关系的模型实例时,Django首先写入对象然后再次进入并写入适当的m2m关系。由于m2m的东西是“第二”,试图在自定义保存中处理关系失败。

解决方案是使用post-save signal.删除自定义保存内容并将其添加到模型定义下方,确保导入receiverpost_save

@receiver(post_save, sender = Content)
def update_m2m_relationships_on_save(sender, **kwargs):
    if not kwargs['instance'].is_tagged:
        tag_content(kwargs['instance'].pk)

您的tag_content函数可能应该将is_tagged交换为True,然后保存实例;如果那个布尔值永远不会翻转那么这可能只是在无限循环中运行。您也可以传入对象而不是传入pk:

def tag_content(thing_to_tag):
    thing_to_tag.tags.add([1,2,3])
    thing_to_tag.is_tagged = True
    thing_to_tag.save()
    return thing_to_tag

请注意.add()的使用,这在添加m2m关系时非常重要。