如何将原始SQL转换为Django QuerySet?附相关模型代码
将原始SQL转换为Django QuerySet
核心逻辑拆解
原始SQL的核心行为是:
- 查询
TblKnowledge中满足状态条件的记录 - 左关联
TblUsedKnowledge统计每个知识的使用次数 - 按使用次数倒序排序
- 仅返回指定字段
转换后的QuerySet实现
首先导入必要的模块:
from django.db.models import Q, Count, Exists, OuterRef from KnowledgeManagement.models import TblKnowledge, TblUsedKnowledge
基础版本(假设Status=1是TblKnowledge的字段)
knowledges = TblKnowledge.objects.filter( # 匹配原始SQL的逻辑优先级:(register_status=7) OR (register_status=9 AND Status=1) Q(register_status=TblKnowledge.its_knowledge) | Q(register_status=TblKnowledge.accepted_by_security, Status=1) ).annotate( # 统计每个知识的使用次数,左关联自动处理无使用记录的情况(计数为0) use_count=Count('tblusedknowledge') ).order_by( # 按使用次数倒序排序 '-use_count' ).values( # 指定需要返回的字段,与原始SQL的SELECT对应 'KnowledgeCode', 'KnowledgeTitle', 'CreateDate', 'CreatorUserID_id' )
模型字段修正说明
注意:你提供的TblKnowledge和TblUsedKnowledge模型中没有定义Status字段,这与原始SQL中的Status=1条件冲突。如果Status是TblUsedKnowledge的字段,需要用子查询保留左关联的语义(避免过滤掉无使用记录的知识),代码调整为:
knowledges = TblKnowledge.objects.filter( Q(register_status=TblKnowledge.its_knowledge) | Q( register_status=TblKnowledge.accepted_by_security, # 子查询判断是否存在符合条件的使用记录 Exists( TblUsedKnowledge.objects.filter( knowledge=OuterRef('pk'), Status=1 ) ) ) ).annotate( use_count=Count('tblusedknowledge') ).order_by( '-use_count' ).values( 'KnowledgeCode', 'KnowledgeTitle', 'CreateDate', 'CreatorUserID_id' )
返回模型实例而非字典
如果需要返回TblKnowledge模型实例(而非字典),将values()替换为only()以减少查询字段:
knowledges = TblKnowledge.objects.filter( Q(register_status=TblKnowledge.its_knowledge) | Q(register_status=TblKnowledge.accepted_by_security, Status=1) ).annotate( use_count=Count('tblusedknowledge') ).order_by( '-use_count' ).only( 'KnowledgeCode', 'KnowledgeTitle', 'CreateDate', 'CreatorUserID' )
关键对应点说明
- 左关联:Django ORM通过
annotate(Count('tblusedknowledge'))自动完成左关联,tblusedknowledge是反向关联的默认名称(因TblUsedKnowledge的外键未指定related_name)。 - 逻辑条件:用
Q对象严格复刻原始SQL的逻辑优先级,避免因运算符优先级导致的过滤错误。 - 分组:由于
KnowledgeCode是TblKnowledge的主键,Django ORM在使用annotate时会自动按主键分组,无需额外指定group_by。
内容的提问来源于stack exchange,提问作者siasanaee
相关产品推荐
相关产品推荐

