如何在保存后不使用refresh_from_db的情况下强制Django模型重新加载字段?

时间:2019-06-06 09:32:56

标签: python django orm model

我有以下Django模型: 设备具有部署的外键 我在Device中有采用方法,可以为设备设置部署并执行一些其他逻辑。

请注意,我将id而不是Deployment实例传递给采用方法

class Device(Model):
    id = models.UUIDField(primary_key=True)
    deployment = models.ForeignKey(
        Deployment, on_delete=models.SET_NULL, blank=True, null=True, related_name='devices'
    )

    def adopt(self, deployment_id):
        self.deployment_id = deployment_id
        self.full_clean()

        with transaction.atomic():
            self.save()

            # self.refresh_from_db()

            if self.deployment.private: # this might fail.. see examples
                # additional logic
                pass


class Deployment(TimeStampedModel, DeploymentResource):
    id = models.UUIDField(primary_key=True)
    name = models.CharField(max_length=150)
    private = models.BooleanField(default=False)

如果我不访问Device实例的部署字段,则accept()会按预期工作。 例如:

device = Device.objects.get(pk=device_id)
device.adopt(deployment_id) # this works

相反,如果我在调用“领养”之前加载了部署字段,那么当我致电“领养”时,我得到了AttributeError: 'NoneType' object has no attribute 'private'

这不起作用:

device = Device.objects.get(pk=device_id)
print(device.deployment) # example of accessing/loading the field/relation
device.adopt(deployment_id) # this will generate the attribute error

原因很明显。 device.deployment为None,其值已加载并存储在模型内部,但不会自动重新加载并在save()调用后替换为新的部署。 第一个示例之所以起作用,仅仅是因为在保存之前从未访问过部署关系。

一个明显的解决方案是保存后调用refresh_from_db(请参阅accept方法中的注释),但这会生成一个我想避免的附加查询。 有没有一种方法可以迫使模型忘记不涉及其他查询的部署属性的“缓存”值?

编辑:阐明引发异常的位置

1 个答案:

答案 0 :(得分:0)

我不确定我是否理解正确,但对我来说似乎是问题所在,而部署的默认值为null。 因此,如果您尝试在不首先分配部署对象的情况下访问部署,它将为null。

请在致电device.deployment之前检查您是否正在分配部署,如果是,请提供一些代码,以便我重新创建您的情况。