我有以下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方法中的注释),但这会生成一个我想避免的附加查询。 有没有一种方法可以迫使模型忘记不涉及其他查询的部署属性的“缓存”值?
编辑:阐明引发异常的位置
答案 0 :(得分:0)
我不确定我是否理解正确,但对我来说似乎是问题所在,而部署的默认值为null。 因此,如果您尝试在不首先分配部署对象的情况下访问部署,它将为null。
请在致电device.deployment之前检查您是否正在分配部署,如果是,请提供一些代码,以便我重新创建您的情况。