如何在Django中设置ManyToMany字段的值?

17
在学习Django进行Web编程时,我遇到了这个问题。我在谷歌和Django官方网站上搜索,但找不到任何答案。请帮帮我。
系统环境:
1. Fedora 18 2. Python 2.7 3. Django 1.5.1 4. Eclipse + PyDev
运行时环境: Django的开发服务器
我的模型包括一个ManyToMany字段。当我通过Django的管理面板设置值时,一切都很顺利。下面是我所有模型的代码:
class Posts(models.Model):
    post_authorid = models.IntegerField(verbose_name=u'Authorid')
    post_date = models.DateTimeField(auto_now_add=True,verbose_name=u'PostDate')
    post_date_modified = models.DateTimeField(auto_now=True,verbose_name=u'LastModifiedTime')
    post_content = models.TextField(verbose_name=u'Content')
    post_title = models.CharField(max_length=50,verbose_name=u'Title')
    post_name = models.CharField(max_length=50,blank=True,verbose_name=u'ShortName') 
    post_cover = models.CharField(max_length=200,verbose_name=u'CoverUrl')      
    post_introduction = models.CharField(max_length=500,blank=True,verbose_name=u'introduction')
    post_status = models.ForeignKey(Status,verbose_name=u'status')
    comment_status = models.BooleanField(verbose_name=u'show_comments')
    post_password = models.CharField(max_length=20,blank=True,verbose_name=u'passwd')
    post_tagid = models.ManyToManyField(Tags,verbose_name=u'tag')
    post_threadtypeid = models.ForeignKey(ThreadTypes,verbose_name=u'ThreadType')
    post_comment_conut = models.IntegerField(verbose_name=u'CommentsCount')
    post_comments = models.ManyToManyField(Comments,blank=True,verbose_name=u'Comment')
    def __unicode__(self):
        return u"%s %s %s" % (self.id,self.post_title,self.post_date)
    class Meta:
        ordering = ['post_date']
class Tags(models.Model):
    tagname = models.CharField(max_length=20,verbose_name=u'标签名称')
    def __unicode__(self):
        return u"%s %s" % (self.id,self.tagname)
    class Meta:
        ordering = ['id']

在我的Python shell中,我输入:

post = Posts()

post.post_tagid = Tags.objects.get(id='1')

接着Django会抛出一个HTTP 500错误:

在使用这个多对多关系之前,“posts”字段需要有一个值。

但是,当我使用以下代码时:

post= Posts.objects.get(id='1')

注意-我已经通过Django管理界面输入了“Posts”对象。

接下来,当我使用

post.post_tagid = Tags.objects.get(id='1')

一切都很顺利。

问:我如何添加一个ManyToMany字段而不会引发这个错误?

2个回答

25

看起来问题在于您试图在M2M表实际创建之前向其中添加内容。

当您运行post = Posts()时,您创建了一个对象在内存中,但不是在数据库中。因此,当您尝试向M2M表中添加新条目时,没有任何引用。(请记住,声明M2M字段会创建一个指向关系两端的记录的新表。)

解决方法是在尝试添加到M2M表之前运行post.save()。(Django管理员会在幕后为您执行此操作。)

因此,尝试这样做:

post = Posts()

# now set up the post (title, name, etc.)

post.save() # adds a new entry to the Posts table

post.post_tagid.add(tag) # now that your post exists in the DB this should work

1
但是 post.post_tagid.add(tag) 对我来说没有保存标签,有什么常见原因吗?我正在使用的代码是在 Post 的 save 方法中:res = super().save() if creating: self.post_tagid.add(self.other_foreignkey_tag_field)即使我尝试在结尾处添加 self.save,它仍然不保存 post_tagid,但 other_foreignkey_tag_field 显示标签字段值已保存。 - Sami

5

您应该阅读官方的Django文档,了解有关多对多关系的内容。

在您的情况下,以下代码应该会有所帮助:

# Post object
post= Posts.objects.get(id=1)

# Two tag objects
tag1 = Tags.objects.get(id=1)
tag2 = Tags.objects.get(id=2)


# Add tag objects to Post object
post.post_tagid.add(tag1, tag2)

谢谢您的帮助,但是无论我使用post.post_tagid.add()还是使用'='运算符,Django都会引发相同的错误。 - kidney win
我按照这份文档操作,但是什么也没有得到,问题还是存在的。https://docs.djangoproject.com/en/1.5/ref/models/relations/#django.db.models.fields.related.RelatedManager - kidney win
当我使用dir(post)时,Python向我展示了它具有属性'post_tagid',但是当我输入'post.post_tagid'时,相同的错误信息出现了。 - kidney win
还需要什么吗? - kidney win

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接