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

Django 2.0.0中基于关联Project高效筛选ToolResult的方法

高效筛选关联特定Project的ToolResult方案

首先先明确你的模型结构(方便参考):

from django.db import models
from django.contrib.contenttypes.models import ContentType
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
from django.utils.translation import gettext_lazy as _

class Project(models.Model):
    name = models.CharField(_(u'Name'), max_length=32)

class Domain(models.Model):
    project = models.ForeignKey('projects.Project', on_delete=models.CASCADE)
    tool_result = GenericRelation('projects.ToolResult')

class ToolResult(models.Model):
    content_type = models.ForeignKey(ContentType, on_delete=models.CASCADE)
    object_id = models.PositiveIntegerField()
    content_object = GenericForeignKey('content_type', 'object_id')

你遇到的问题很典型:用content_object__project__in=[1,2]无法过滤,因为GenericForeignKey是Django提供的上层抽象,数据库中并没有对应的外键关联,所以Django没办法将这个链式查询转换成有效的SQL语句,自然无法生效。而且你的数据量极大(50万Domain、300万ToolResult),遍历对象完全不现实,必须用数据库层面的高效查询方案。

下面给你几个适合大数量级的高效实现方式:

方案一:使用Exists相关性子查询(推荐)

这种方式在数据库层面会生成高效的相关性子查询,避免大的IN集合,性能最优:

from django.db.models import Exists, OuterRef
from django.contrib.contenttypes.models import ContentType

# 获取Domain对应的ContentType
domain_ct = ContentType.objects.get_for_model(Domain)

# 筛选关联指定Project的ToolResult
target_tool_results = ToolResult.objects.filter(
    content_type=domain_ct,
    Exists(
        Domain.objects.filter(
            id=OuterRef('object_id'),  # 关联ToolResult的object_id和Domain的id
            project_id__in=[1, 2]
        )
    )
)

方案二:使用Subquery子查询

如果你的数据库对Exists支持一般,也可以用Subquery先拿到符合条件的Domain ID集合,再过滤ToolResult:

from django.db.models import Subquery
from django.contrib.contenttypes.models import ContentType

domain_ct = ContentType.objects.get_for_model(Domain)

# 子查询获取目标Project下的所有Domain ID
target_domain_ids = Domain.objects.filter(project_id__in=[1,2]).values('id')

# 过滤ToolResult
target_tool_results = ToolResult.objects.filter(
    content_type=domain_ct,
    object_id__in=Subquery(target_domain_ids)
)

方案三:直接用JOIN(Django 2.0兼容)

因为你用的是Django 2.0,也可以用extra直接指定表关联,生成JOIN语句,性能也很可观:

from django.contrib.contenttypes.models import ContentType

domain_ct = ContentType.objects.get_for_model(Domain)

target_tool_results = ToolResult.objects.filter(
    content_type=domain_ct
).extra(
    tables=['projects_domain'],  # 注意替换成你的Domain表实际名称,可通过Domain._meta.db_table查看
    where=[
        'projects_domain.id = toolresult_object_id',  # 关联ToolResult的object_id和Domain的id
        'projects_domain.project_id IN (1, 2)'
    ]
)

注意事项:

  • 确保projects_domain是你的Domain模型对应的数据库表名,一般格式是应用名_模型名,不确定的话可以在Django shell里执行Domain._meta.db_table查看。
  • 这三种方案都是直接在数据库层面完成过滤,不会把大量数据加载到Python内存,完全适配你的百万级数据量场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.27 09:21:16