如何在不使用Raw方法的情况下将SQL查询转换为Django ORM查询?
将目标SQL转换为Django ORM写法(无Raw)
先假设你的BalanceHold模型结构和SQL字段对应(比如包含account_balance、hold_id、transaction_id、release_time、hold_type这些字段),以下是不用raw SQL的实现方式:
1. 导入ORM依赖
首先需要导入Django ORM的相关工具:
from django.db.models import Subquery, OuterRef, Max, Q
2. 构造分组聚合的子查询
原SQL的核心逻辑是按transaction_id分组,分别处理两种release_time的场景,取每组的极值:
- 当
release_time为null时,取该组最大的hold_type - 当
release_time不为null时,取该组最大的release_time
先构造这两个场景的子查询:
# 场景1:release_time为null时,每组的最大hold_type null_release_max_hold = BalanceHold.objects.filter( transaction_id=OuterRef('transaction_id'), account_balance=X, # 替换成你实际的X值(比如账户余额实例或ID) release_time__isnull=True ).values('transaction_id').annotate(max_type=Max('hold_type')).values('max_type') # 场景2:release_time不为null时,每组的最大release_time non_null_release_max_time = BalanceHold.objects.filter( transaction_id=OuterRef('transaction_id'), account_balance=X, release_time__isnull=False ).values('transaction_id').annotate(max_time=Max('release_time')).values('max_time')
3. 筛选符合条件的hold_id
接下来构造子查询,找出每个transaction_id下满足条件的记录(要么是null场景下hold_type等于组内最大值,要么是非null场景下release_time等于组内最大值),并取出这些记录的hold_id:
valid_hold_ids = BalanceHold.objects.filter( transaction_id=OuterRef('transaction_id'), account_balance=X, # 两种场景的或条件 Q( release_time__isnull=True, hold_type=Subquery(null_release_max_hold) ) | Q( release_time__isnull=False, release_time=Subquery(non_null_release_max_time) ) ).values('hold_id')
4. 执行最终查询
最后外层查询筛选出account_balance=X且hold_id在上述子查询结果中的所有记录:
final_result = BalanceHold.objects.filter( account_balance=X, hold_id__in=Subquery(valid_hold_ids) )
注意事项
- 把代码中的
X替换成你实际的account_balance值(比如外键对象或者对应的ID) - 如果
hold_id是模型的主键,逻辑可以进一步简化,但上述写法完全匹配你原SQL的逻辑 - 为了提升查询性能,建议给
transaction_id、account_balance、release_time这些字段添加数据库索引
内容的提问来源于stack exchange,提问作者Itai Bar
相关产品推荐
相关产品推荐

