Django中如何通过模型字段关联查询另一模型字段?
高效实现Django多对多关联的匹配查询
嘿,我来帮你解决这个查询效率低的问题!之前用列表推导式把数据拉到内存里筛选的方式,数据量一大确实会拖垮性能,咱们直接用Django ORM的数据库层面查询来搞定,效率能提升一大截。
方法一:用Exists子查询(最推荐)
这是性能最优的方案,因为它让数据库直接做存在性检查,只返回符合条件的记录,不会拉取多余数据。
首先导入需要的模块:
from django.db.models import Exists, OuterRef
然后构造子查询并筛选:
# 子查询:找到当前Reg对应的、金额等于自身price的交易 matching_transactions = Transaction.objects.filter( reg=OuterRef('pk'), # OuterRef用来引用外层查询的Reg主键 amount=OuterRef('price') ) # 筛选存在符合条件交易的Reg paid_registrations = Reg.objects.filter(Exists(matching_transactions))
为什么这个高效?
数据库会对每个Reg执行一次存在性检查,只要找到任意一条匹配的交易就停止判断,而且整个过程都在数据库内部完成,不用把所有Reg数据加载到Python内存里,数据量越大,优势越明显。
方法二:用annotate标记后筛选
如果你更习惯用annotate的方式,也可以给每个Reg添加一个标记字段,再过滤出标记为True的记录:
先导入需要的模块:
from django.db.models import Case, When, BooleanField, F
然后执行查询:
paid_registrations = Reg.objects.annotate( has_matching_transaction=Case( # 当关联交易的amount等于当前Reg的price时,标记为True When(transactions__amount=F('price'), then=True), default=False, output_field=BooleanField() ) ).filter(has_matching_transaction=True).distinct()
注意事项
因为是多对多关系,查询时可能会返回重复的Reg记录,所以要加上.distinct()去重。不过这种方法的性能略逊于Exists,因为需要额外做字段标注的计算。
对比之前的方案
之前的列表推导式是先把一批Reg数据拉到Python内存,再逐个检查is_paid,当数据量达到几百上千条时,内存占用和耗时都会急剧上升。而上面的两种方法都是让数据库完成所有筛选逻辑,只返回最终符合条件的结果,性能提升非常显著。
内容的提问来源于stack exchange,提问作者Fohlen
相关产品推荐
相关产品推荐

