首页 > 解决方案 > 如何在不使用 refresh_from_db 的情况下强制 Django 模型在保存后重新加载字段?

问题描述

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

请注意,我将 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 = 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(请参阅采用方法中的注释),但这会生成一个我想避免的额外查询。有没有办法强制模型忘记不涉及额外查询的部署属性的“缓存”值?

编辑:澄清引发异常的位置

标签: pythondjangoormmodel

解决方案


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

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


推荐阅读