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

问题描述:

我的内容模型与标记模型具有多对多关系。当我保存一个Content对象时,我想动态地添加这些关系。我以下面的方式做这件事。在Django的保存方法中动态添加多对多关系

# 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 

换句话说,当内容物被保存,它的标签字段与3个不同的标签对象模型。只是为了让你知道,我确实在数据库中有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

不是你问题的原因,但你为什么不将内容项本身传递给tag_content而不是pk?然后你不必从数据库中重新查询它。 –

+0

好点。会做到这一点。但正如你所说,不是解决我的问题。 –

由于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_taggedTrue然后保存实例;如果该布尔值永远不会翻转,那么这可能会在无限循环中运行。你也可以通过在对象,而不是通过在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的关系时,这是非常重要的。

+0

好的,我试过了。但是,我不断收到另一个错误:不可用类型'列表'。它引用了add()函数。任何想法为什么发生这种情况? –

+1

尝试添加一组查询对象而不是数字列表 – souldeux