Django ORM如何实现双列匹配的WHERE IN子查询
Django ORM 实现多字段 WHERE IN 子查询方案
Django ORM 完全支持多字段组合匹配的WHERE IN查询,根据使用的Django版本不同,可以选择以下两种和原生SQL语义完全等价的实现方式,不会出现字段匹配错位的问题。
方案1:Django 3.2+ 原生多列IN支持(与原生SQL逻辑完全一致)
Django 3.2版本新增了Tuple表达式支持多列组合匹配,写法最贴近原生SQL逻辑:
from django.db.models import Subquery from django.db.models.expressions import Tuple # 构造子查询:筛选指定客户持有的许可证的version、type字段 customer_licenses = License.objects.filter( company_id="6f65e5cc-cd1f-4888-a236-38295bae393a" ).values("version", "type") # 主查询:匹配version+type组合在子查询结果内的版本详情记录 version_detail_list = VersionDetails.objects.filter( Tuple("version", "type")__in=Subquery(customer_licenses) )
该写法生成的SQL和给出的原生语句结构完全一致。
方案2:全版本兼容写法(基于EXISTS关联,推荐低版本使用)
如果Django版本低于3.2,可以用Exists关联子查询实现完全相同的语义,所有Django版本都支持,且多数数据库下执行效率和IN查询相当:
from django.db.models import Exists, OuterRef version_detail_list = VersionDetails.objects.annotate( match_license=Exists( License.objects.filter( company_id="6f65e5cc-cd1f-4888-a236-38295bae393a", version=OuterRef("version"), type=OuterRef("type") ) ) ).filter(match_license=True)
注意事项
- 不要尝试分开为两个字段单独写
__in条件,类似下面的错误写法会出现字段组合错位:
# 错误写法:会匹配到(version=v1, type=t2)这类不存在于子查询的错误组合 bad_case = VersionDetails.objects.filter( version__in=customer_licenses.values("version"), type__in=customer_licenses.values("type") )
这种写法相当于对两个字段分别做范围匹配,而非组合匹配,返回结果会多出不符合要求的记录。
内容的提问来源于stack exchange,提问作者MrGlass
相关产品推荐
相关产品推荐

