为什么Django报告此实例属性的值不一致?

时间:2016-09-03 08:21:39

标签: python django django-models django-queryset

我有以下简单的Django模型类:

from django.db import models

class MyClassA(models.Model):
    name = models.CharField(max_length=254)
    parent_a = models.IntegerField()

    def update_names(self, name, other_a_list):
        a_set = set([self] + other_a_list)
        for curr_a in a_set:
            curr_a.name = name
            curr_a.save()
            print "Updated MyClassA #%s's name to %s" % (curr_a.pk, curr_a.name)

    def related_a_instances(self):
        family_list = MyClassA.objects.filter(parent_a=self.parent_a)
        return [curr_a for curr_a in family_list if curr_a.name == "CREATED"]

当我运行以下代码时,最后一个断言失败:

    m1 = MyClassA.objects.create(parent_a=99, name="OPEN",)
    m2 = MyClassA.objects.create(parent_a=99, name="CREATED",)
    assert m2.name == "CREATED"

    m3 = MyClassA.objects.create(parent_a=99, name="CREATED",)
    assert m3.name == "CREATED"

    related_a_instances = m2.related_a_instances()
    assert related_a_instances == [m2, m3]

    m2.update_names(name="OPEN", other_a_list=related_a_instances)

    print "Checking that MyClassA m1 (%s) is OPEN. My Code says its %s. DB says %s" % (m1.pk, m1.name, MyClassA.objects.get(pk=m1.pk).name)
    assert m1.name == "OPEN"
    print "Checking that MyClassA m2 (%s) is OPEN. My Code says its %s. DB says %s" % (m2.pk, m2.name, MyClassA.objects.get(pk=m2.pk).name)
    assert m2.name == "OPEN"
    print "Checking that MyClassA m3 (%s) is OPEN. My Code says its %s. DB says %s" % (m3.pk, m3.name, MyClassA.objects.get(pk=m3.pk).name)
    assert m3.name == "OPEN"

以下是发生故障时的控制台输出:

Updated MyClassA #2's name to OPEN
Updated MyClassA #3's name to OPEN
Checking that MyClassA m1 (1) is OPEN. My Code says its OPEN. DB says OPEN
Checking that MyClassA m2 (2) is OPEN. My Code says its OPEN. DB says OPEN
Checking that MyClassA m3 (3) is OPEN. My Code says its CREATED. DB says OPEN

为什么调用函数在m3.status明确更新为'CREATED'时认为'OPEN'update_names()

奇怪的是,如果我用m2.update_names(name='OPEN', other_a_list=related_a_instances)替换m2.update_names(name='OPEN', other_a_list=[m2,m3]),则所有断言都会通过。这里发生了什么?我很难过!

1 个答案:

答案 0 :(得分:2)

因为您还没有从数据库刷新m3。 related_a_instances从数据库中获取全新的对象;即使这些项引用与m1到m3相同的db行,它们也不是同一个对象,对一个对象的更新不会影响另一个。

如果您在断言之前做过m3 = MyClassA.objects.get(pk=m3),您会看到更改。

您的替代方法通过的原因是您 将相同的对象m3发送到更新方法。