我有这两个模型:
Parent(models.Model):
name=models.CharField(max_length=10)
Child(models.Model):
parent=models.ForeignKey(Parent)
name=models.CharField(max_length=10)
我正在寻找一种有效的方法来删除没有孩子的父母。目前,我正在使用RAW SQL:
from django.db import connection
SQL="DELETE FROM app_parent WHERE app_parent.id NOT IN (SELECT id FROM app_child"
哪个运行两个查询,我仍然想使用Django ORM。对于ORM,我首先获得孩子列表,然后检查父ID是否存在。
有更快的方法吗?
答案 0 :(得分:1)
LEFT OUTER JOIN
您可以Parent
使用.filter(..)
检测没有孩子的related_name
,并检查该关系__isnull
。
所以我们可以通过写一下 no 孩子的Parent
列表:
Parent.objects.filter(child__isnull=True).distinct()
.distinct()
在这里很重要,否则父母可以多次次。在窗帘后面,Django将执行一个看起来像这样的查询:
SELECT DISTINCT `parent`.*
FROM `parent`
LEFT OUTER JOIN `child` ON (`parent`.`id` = `child`.`parent_id`)
WHERE (`child`.`id` IS NULL)
我们可以.delete()
Parent
s:
Parent.objects.filter(child__isnull=True).distinct().delete()
EXISTS
查询我们也可以使用存在的查询:
from django.db.models import Exists, OuterRef
Parent.objects.annotate(
has_children=Exists(
Child.objects.filter(parent=OuterRef('pk').values('id'))
)
).where(has_children=False).delete()
因此,我们在每个Parent
注释Child
是否存在parent
,pk
的{{1}}这一事实。然后我们Parent
注意这个注释应该是.filter(..)
。
这将产生如下查询:
False
但请注意,如果仍然通过其他SELECT `parent`.*
FROM `parent`
WHERE NOT EXISTS (
SELECT `child`.`id`
FROM `child`
WHERE `child`.`parent_id` = `parent`.`id`
) = True
引用Parent
,则可能会失败。例如,如果不仅有一个孩子,而是一个引用ForeignKey
的{{1}}关系,那么Uncle
可能会失败,因为仍有Parent
个指没有孩子的一个或多个.delete()
。