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

Posted

技术标签:

【中文标题】在Django的save方法中动态添加多对多关系【英文标题】:Dynamically adding many to many relationships in the save method in Django 【发布时间】:2016-12-29 05:42:05 【问题描述】:

我的内容模型与标签模型具有多对多的关系。当我保存一个 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 版本可以工作,而另一个不能呢?任何帮助表示赞赏。

【问题讨论】:

不是你的问题的原因,但你为什么不将内容项本身传递给tag_content,而不是pk?这样你就不必从数据库中重新查询它了。 好点。会这样做。但正如你所说,这不是我问题的解决方案。 【参考方案1】:

由于 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 关系时很重要。

【讨论】:

好的,我试过了。但是,我不断收到另一个错误:Unhashable type 'list'。它引用了 add() 函数。知道为什么会这样吗? 尝试添加一组查询对象而不是数字列表

以上是关于在Django的save方法中动态添加多对多关系的主要内容,如果未能解决你的问题,请参考以下文章

IOS/Core-Data:添加多对多关系

如何首先使用代码向 Identity 默认表 AspNetUsers 添加多对多关系?

添加多对多关系时检测重复插入

如何添加多对多的额外数据透视列?

在放大graphql中添加多对多连接

EF Core 5.0 添加多对多使得一对多无法确定