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

Why is Django reporting inconsistent values for this instance attribute?

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

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

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

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

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

如果您在断言之前m3 = MyClassA.objects.get(pk=m3),您会看到变化。

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