我有一个一对多的关系,我想在多方的最后一个引用对象被删除后自动删除一方。也就是说,我要进行垃圾回收,或者做一种反向级联操作。
我试图通过使用 Django 的 post_delete 信号来解决这个问题。这是我正在尝试做的一个简化示例:
模型.py
class Bar(models.Model):
j = models.IntegerField()
# implicit foo_set
class Foo(models.Model):
i = models.IntegerField()
bar = models.ForeignKey(Bar)
def garbage_collect(sender, instance, **kwargs):
# Bar should be deleted after the last Foo.
if instance.bar.foo_set.count() == 0:
instance.bar.delete()
post_delete.connect(garbage_collect, Foo)
这在使用时有效Model.delete
,但QuerySet.delete
它会严重破坏。
测试.py
class TestGarbageCollect(TestCase):
# Bar(j=1)
# Foo(bar=bar, i=1)
# Foo(bar=bar, i=2)
# Foo(bar=bar, i=3)
fixtures = ['db.json']
def test_separate_post_delete(self):
for foo in Foo.objects.all():
foo.delete()
self.assertEqual(Foo.objects.count(), 0)
self.assertEqual(Bar.objects.count(), 0)
这工作得很好。
tests.py 继续
def test_queryset_post_delete(self):
Foo.objects.all().delete()
self.assertEqual(Foo.objects.count(), 0)
self.assertEqual(Bar.objects.count(), 0)
这会在第二次发出信号时中断,因为正如Django 的文档所说,QuerySet.delete
它会立即应用,并且instance.bar.foo_set.count() == 0
在第一次发出信号时就已经是真的了。仍然从文档中读取,将为每个已删除的对象QuerySet.delete
发出信号,并在被删除后被调用。post_delete
garbage_collect
Bar
那么问题来了:
- 有没有更好的垃圾收集一对多关系一侧的方法?
- 如果没有,我应该改变什么才能使用 QuerySet.delete?