Django ManyToMany Equality

时间:2013-04-17 19:25:34

标签: python django

我有一个模型,Entry.特别值得注意的是它的addTags函数,它将标记添加到Entry的实例并保存。以下是该类的完整代码:

class Entry(models.Model):

    title = models.CharField(max_length=80)
    author = models.ForeignKey(User)
    pubdate = models.DateTimeField()
    tags = models.ManyToManyField(Tag)
    text = models.TextField()

    def getAllTags(self):
        '''
        Returns all tags applied to a given entry
        '''
        return self.tags.all()

    def addTag(self, tagName):
        '''
        Add a tag to an entry. If tag does not exist, create it. If tag has
        already been added, do nothing.
        '''
        try:
            tag = Tag.objects.get(name=tagName)
            return tag
        except Tag.DoesNotExist:
            tag = self.tags.create(name=tagName)
            self.save()
            return tag

奇怪的是,当我使用以下代码测试addTag函数时(之前创建的entry1是一个有效的Entry对象):

    tag1 = entry1.addTag("testtag2")
    tag2 = entry1.addTag("testtag2")
    tag3 = entry1.addTag("testtag3")
    tagList = [tag1, tag2, tag3]
    for listTag, objTag in zip(tagList, entry1.tags.all()):
        print "%s: %s" % (listTag, objTag)
    self.assertEqual(entry1.tags.all(), tagList)

我收到以下断言错误:

AssertionError: [<Tag: testtag>, <Tag: testtag2>, <Tag: testtag3>] != [<Tag: testtag>, <Tag: testtag2>, <Tag: testtag3>]

然而,上面代码中的print语句给出了以下内容:

testtag: testtag
testtag2: testtag2
testtag3: testtag3

表示已按预期创建标记。似乎每个标记对象的不同内存位置都已创建,但我不知道这是怎么回事。思考?

2 个答案:

答案 0 :(得分:2)

self.assertEqual(list(entry1.tags.all()), tagList)

entry1.tags.all()是一个不覆盖__eq__方法的查询集,因此通过它的id(内存位置)与其他对象进行比较。如果要将它返回的对象与tagList中的对象进行比较,则必须首先通过调用list来评估查询集。

列表中的条目实例(entry1.tags.all())与tagList中的实例不同。这并不会改变两个列表相同,因为Entry实例确实有一个重写的__eq__方法,并通过它们的pk进行比较。

编辑:

将QuerySet与列表进行比较时

entry1.tags.all() == tagList

您没有比较它返回的实例,因为Queryset没有覆盖__eq__方法,因此无法与列表进行比较。

然而,可以比较两个列表。列表中的所有实例都是成对比较的,因为它们的__eq__提供了除id-comparison之外的其他方法(它测试pk相等性),它们进行了比较。

答案 1 :(得分:0)

尝试重构代码:

    class Entry(models.Model):

        title = models.CharField(max_length=80)
        author = models.ForeignKey(User)
        pubdate = models.DateTimeField()
        tags = models.ManyToManyField(Tag)
        text = models.TextField()

        def getAllTags(self):
            '''
            Returns all tags applied to a given entry
            '''
            return self.tags.all()

        def addTag(self, tagName):
            '''
            Add a tag to an entry. If tag does not exist, create it. If tag has
            already been added, do nothing.
            '''
            tag = Tag.objects.get_or_create(name=tagName)
            self.tags.add(tag)
            self.save()

此外,在测试中,您必须比较两个列表:

self.assertEqual(list(entry1.tags.all()), tagList)