如何用Django ORM对无关联模型执行左外连接查询?
Django ORM实现无外键模型的差集查询
问题描述
现有两个无外键关联的Django模型:
class One(models.Model): name = models.CharField(max_length=300, unique=True) class Two(models.Model): name = models.CharField(max_length=300, unique=True)
需要找出name未出现在Two表中的One实例,对应的目标SQL是:
select app_one.name from app_one left join app_two on app_one.name = app_two.name where app_two.name is null group by 1;
不想用那种“查询One所有name再用IN判断不在Two里”的方案(扩展性太差),询问是否可以通过Django ORM实现该查询,还是必须编写原生SQL?
解决方案
当然可以用Django ORM实现,不用写原生SQL。有两种常用方案,都能生成和目标SQL等价的高效查询,不会出现内存占用过高的问题:
方案一:使用Subquery+OuterRef
from django.db.models import OuterRef, Subquery # 构造子查询,匹配当前One的name是否存在于Two中 two_name_subquery = Two.objects.filter(name=OuterRef('name')).values('name') # 筛选One中不在子查询结果里的实例 result = One.objects.exclude(name__in=Subquery(two_name_subquery))
这个写法生成的SQL逻辑和你提供的左连接完全一致,不会把所有name加载到内存,适合大数据量场景。
方案二:使用Exists子查询
from django.db.models import Exists, OuterRef # 判断当前One的name是否存在于Two中的存在性子查询 name_exists_in_two = Exists(Two.objects.filter(name=OuterRef('name'))) # 筛选不存在的实例 result = One.objects.filter(not name_exists_in_two)
这种写法更直观,生成的SQL会用NOT EXISTS子句,性能和左连接方案相当,同样具备良好的扩展性。
两种方案都避开了你提到的扩展性差的IN查询问题,完全满足需求。
内容的提问来源于stack exchange,提问作者dfrankow
相关产品推荐
相关产品推荐

