Django:assertEquals 与 QuerySet 在视觉上相等的结果

Django: assertEquals with visually equal result with QuerySet

任何人都可以解释为什么它们具有相同的值,但不比较相等吗?很难理解这一点。使它们成为 "equal" 的最佳方法是什么?

使用 ipdb 检查:

ipdb> expected_value                                                                                                                                  
{'author': 'john', 'id': 1, 'title': 'Yesterday', 'body': 'All my troubles seemed so far away', 'tags': <QuerySet ['Music', 'Lyrics']>}
ipdb> response                                                                                                                                        
{'author': 'john', 'id': 1, 'title': 'Yesterday', 'body': 'All my troubles seemed so far away', 'tags': <QuerySet ['Music', 'Lyrics']>}

代码段:

class TestPost(TestCase):                                                                                               

    def test_serialize(self):                                                                                           
        user = User.objects.create(username="john", password="12345678", email="john@exemplo.com")                      
        tag1 = Tag.objects.create(value="Music")                                                                        
        tag2 = Tag.objects.create(value="Lyrics")                                                                       
        post = Post.objects.create(author=user, title="Yesterday", body="All my troubles seemed so far away")           
        post.tags.add(tag1)                                                                                             
        post.tags.add(tag2)                                                                                             

        expected_value = {                                                                                              
            "author": user.username,                                                                                    
            "id": user.id,                                                                                              
            "title": post.title,                                                                                        
            "body": post.body,                                                                                          
            "tags": post.tags.all().values_list("value", flat=True),                                                    
        }                                                                                                               
        response = post.serialize()                                                                                                                                      
        self.assertEqual(expected_value, response)

以及我正在测试的 Django 模型

class Post(models.Model):                                                                                               
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE, blank=False, null=False,)            
    title = models.CharField(blank=False, null=False, validators=[MinLengthValidator(3)], max_length=50)                
    body = models.CharField(blank=False, null=False, validators=[MinLengthValidator(5)], max_length=1000)               
    tags = models.ManyToManyField("Tag")                                                                                

    def serialize(self):                                                                                                
        return {                                                                                                        
            "author": self.author.username,                                                                             
            "id": self.id,                                                                                              
            "title": self.title,                                                                                        
            "body": self.body,                                                                                          
            "tags": self.tags.all().values_list("value", flat=True),                                                    
        } 

Can anybody explain me why these have the same values, but don't compare equal?

因为两个 QuerySet objects [GitHub] 在 "carry" 相同的值时不被认为是相等的。只有对象本身相同,才会认为是相等的。实际上,如果您在 shell 中对此进行测试,您会检索到:

>>> MyModel.objects.all() == MyModel.objects.all()
False
>>> qs = MyModel.objects.all()
>>> qs == qs
True

毕竟一个QuerySet不仅是一个值的集合,也是一个查询,检查两个查询是否等价,可能是一个undeciable problem [wiki].

因此您可以将其转换为带有 list(…) 的列表,例如:

expected_value = {
    'author': user.username,
    'id': user.id,
    'title': post.title,
    'body': post.body,
    'tags': <b>list(</b>post.tags.values_list('value', flat=True)<b>)</b>,
}

以及在序列化程序中:

class Post(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL, on_delete=models.CASCADE)
    title = models.CharField(validators=[MinLengthValidator(3)], max_length=50)
    body = models.CharField(validators=[MinLengthValidator(5)], max_length=1000)
    tags = models.ManyToManyField("Tag")

    def serialize(self):
        return {
            'author': self.author.username,
            'id': self.id,
            'title': self.title,
            'body': self.body,
            'tags': <b>list(</b>self.tags.values_list('value', flat=True)<b>)</b>
        }