在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. 删除自定义保存内容并将其添加到您的模型定义下方,确保导入receiver
和post_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方法中动态添加多对多关系的主要内容,如果未能解决你的问题,请参考以下文章