如何解决为什么 Django ORM 在 post_delete 信号中找不到相关对象?
当我删除 PumpLog 时,我会通过 on_delete = models.CASCADE 删除相关的发票。发票具有 post_delete 信号,用于查询该关系(请参阅带有 #ERROR
的行)。
事情是这样的:用户删除 PumpLog -> 触发删除发票 -> 触发发票 post_delete 信号
models.py
class PumpLog(BasicModelFields):
gallons = models.PositiveIntegerField(blank=True,null=True,editable=False)
class Invoice(models.Model):
pump_log = models.ForeignKey('PumpLog',on_delete = models.CASCADE)
def post_invoice_delete(sender,instance,**kwargs):
instance.pump_log #ERROR
# or
print(instance.pump_log_id) #displays the correct id. But the below query fails.
PumpLog.objects.filter(index = instance.pump_log_id) #ERROR
错误:
records.models.PumpLog.DoesNotExist: PumpLog matching query does not exist.
我在某种程度上理解 PumpLog 可以被删除according to the docs:
注意对象将不再存在于数据库中,所以要非常 小心你用这个实例做什么。
从技术上讲,此警告在这种情况下是指发票,而不是 PumpLog。另外在PGAdmin中我可以直接查询数据库,看到PumpLog和Invoice还在那里。
那么为什么 ORM 无法找到 PumpLog?
PumpLog 是否人为地从 ORM 的范围中删除,即使它尚未从数据库中删除?还是我没有正确理解这一点?
编辑:
class BasicModelFields(models.Model):
modified = models.DateTimeField('Last Updated',auto_now=True,blank=True)
created = models.DateTimeField('Created',auto_now_add=True,blank=True)
created_by = models.ForeignKey(Profile,related_name='%(class)s_created_by_user',verbose_name = 'Created By',on_delete=models.SET_NULL,blank=True,editable=False)
modified_by = models.ForeignKey(Profile,related_name='%(class)s_modified_by_user',verbose_name = 'Modified By',editable=False)
auto_complete_look_up_field = models.CharField(max_length=200,db_column='AutoCompleteLookUpField',editable=False)
header_field = models.CharField(max_length=200,editable=False)
history = AuditlogHistoryField(editable=False) #maybe add to BasicModelFields
class Meta:
abstract = True
解决方法
我相信这里的事件顺序是这样的:
-
PumpLog
对象从数据库中删除。 -
Invoice
对象从数据库中删除。 - 在
post_invoice_delete
中,您可以访问 Invoice 实例。但是,无法访问 PumpLog 实例/数据库记录,因为它只能在 PumpLog post_delete 挂钩接收器内部访问。
因此,当您尝试访问 instance.pump_log
时,您会收到一个DoesNotExist 异常,因为简单地说,PumpLog 对象不再存在于数据库中或任何地方。
我相信该行只返回 None 而不是引发DoesNotExist 异常。
PumpLog.objects.filter(index = instance.pump_log_id)
如果您使用 get()
代替 filter()
,它应该只引发异常。
至于为什么仍然可以访问 instance.pump_log__id
,我认为这仅仅是因为 Invoice
实例本身可以访问 pump_log 的 ID 作为 ForeignKey
列的结果可能存在于数据库中,因此转换为对象本身的属性,使 ORM 无需访问数据库。只有当您执行一些需要从数据中读取 PumpLog
对象的操作时,您才会收到错误消息。
如果您确实需要访问 PumpLog
实例,也许您应该在 post_log_post_delete
接收器中执行您需要执行的操作,它应该能够访问 Invoice 实例,因为那可能仍然存在。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。