You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何通过无直接关联的复杂查询获取Django模型数据

问题:通过Django模型复现复杂关联查询获取EIH数据

现有简化后的Django模型结构如下:

class PE(models.Model): # table p_e
    p_e_id = models.AutoField(primary_key=True)
    p_o = models.ForeignKey('PO', models.DO_NOTHING)
    p_r = models.ForeignKey('PR', models.DO_NOTHING)
    s_o = models.ForeignKey('SO', models.DO_NOTHING)
    item = models.ForeignKey(Items, models.DO_NOTHING, related_name='pe_item')
    p_e_is_possible = models.BooleanField()

class EIH(models.Model): # table e_i_h
    e_i_h_id = models.AutoField(primary_key=True)
    target_item = models.ForeignKey('Items', models.DO_NOTHING,related_name='target_item')
    component_item = models.ForeignKey('Items', models.DO_NOTHING,related_name='component_item')
    p_o = models.ForeignKey('PO', models.DO_NOTHING)
    p_r = models.ForeignKey('PR', models.DO_NOTHING)

class Items(models.Model):
    item_id = models.AutoField(primary_key=True)

当前使用的原生SQL查询逻辑是:

SELECT * FROM p_e
INNER JOIN e_i_h ON e_i_h.target_item_id = p_e.item_id AND e_i_h.component_item_id = -1  AND
    (e_i_h.p_o_id = p_e.p_o_id OR
    (p_e.p_e_is_possible = True AND p_e.s_o_id != -1)
    )

需求是仅通过Django ORM获取符合上述SQL条件的EIH数据集,但尝试的关联查询无法正确引用PE模型的字段(如p_e_is_possible),比如以下写法存在问题:

pe_queryset = PE.objects.filter(item_id=15)
for pe in pe_queryset:
    erp = EIH.objects.get(Q(p_o_id= pe.p_o.p_o_id) | Q(pe.p_e_is_possible=True),
                          item_id=pe.item.item_id, component_item_id=-1)

或:

erp = EIH.objects.get(Q(p_o_id= pe.p_o.p_o_id) | Q(target_item__p_e__p_e_is_possible=True),
      item_id=pe.item.item_id, component_item_id=-1)

问题在于无法正确将PE的字段条件关联到EIH的查询中,如何复现原SQL的查询逻辑?


解决方案

可以通过Django的Q对象、F表达式和反向关联(利用Items的related_name)直接复现原生SQL的内连接逻辑,无需循环查询:

from django.db.models import Q, F

# 构建符合条件的EIH查询集
eih_queryset = EIH.objects.filter(
    # 对应SQL中的 e_i_h.component_item_id = -1
    component_item_id=-1,
    # 通过反向关联关联PE表,对应 e_i_h.target_item_id = p_e.item_id
    target_item__pe_item__isnull=False,
).filter(
    # 复现SQL中的OR条件分支
    Q(p_o_id=F('target_item__pe_item__p_o_id')) |
    Q(target_item__pe_item__p_e_is_possible=True, target_item__pe_item__s_o_id__ne=-1)
).distinct()

关键说明:

  1. 反向关联引用:target_item__pe_item是通过Items模型中PE的related_name='pe_item'实现的反向关联,对应SQL中e_i_h.target_item_id = p_e.item_id的关联逻辑。
  2. F表达式:F('target_item__pe_item__p_o_id')用于在查询中直接引用关联表的字段值,实现e_i_h.p_o_id = p_e.p_o_id的等值匹配。
  3. Q对象组合:用|连接两个Q对象,精准复现原生SQL中的OR条件分支。
  4. distinct():如果存在一对多关联导致重复数据,用distinct()去重,确保结果和原生SQL一致。

如果需要筛选特定item_id(比如示例中的15),只需在过滤条件中添加:

target_item__item_id=15

最终完整查询:

eih_queryset = EIH.objects.filter(
    component_item_id=-1,
    target_item__item_id=15,
    target_item__pe_item__isnull=False,
).filter(
    Q(p_o_id=F('target_item__pe_item__p_o_id')) |
    Q(target_item__pe_item__p_e_is_possible=True, target_item__pe_item__s_o_id__ne=-1)
).distinct()

内容的提问来源于stack exchange,提问作者Will Heeme

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 02:50:05