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

Django中无中间表场景下如何处理多对多关联关系?

场景处理与查询优化方案

即时查询优化

你原有写法性能差的核心原因是将Subscription的account_number查询结果转成了Python列表,导致ORM生成超长的IN参数列表,同时多了一次数据从数据库到Python层的传输开销。直接将未执行的QuerySet作为__in的参数即可,Django ORM会自动将其转换为数据库层面的子查询,不会生成超长查询语句:

# 直接传入values生成的QuerySet,不要转list
customers = Customer.objects.filter(account_number__in=subscriptions.values("account_number"))

生成的SQL结构为:

SELECT * FROM customer WHERE account_number IN (SELECT account_number FROM subscription WHERE [你原有subscription的过滤条件])

如果需要更高的查询性能,可以直接用连表的Raw SQL查询,效率优于子查询:

# 把WHERE后的条件替换为你实际筛选Subscription的逻辑
customers = Customer.objects.raw("""
    SELECT DISTINCT c.* 
    FROM customer c 
    INNER JOIN subscription s ON c.account_number = s.account_number
    WHERE s.xxx = %s
""", [筛选参数])

注意:两个模型的account_number字段必须单独加索引,否则所有关联查询的性能都无法达标。


这类特殊关联场景的长期处理方案

你当前的表结构本质是多对多关系通过共享字段隐式关联,不符合常规的数据库设计规范,后续维护成本会越来越高,建议按优先级选择以下方案优化:

  • 新增Account模型,将account_number设为主键,把Customer和Subscription的account_number字段改为指向Account的外键,设置db_constraint=False避免强制生成数据库外键约束,不需要修改现有数据即可适配Django ORM的标准关联查询逻辑,后续可以直接用双下划线跨表查询。
  • 如果暂时不能新增表,可在两个模型中封装自定义关联方法,把优化后的查询逻辑统一收口,避免业务代码重复写关联查询逻辑,示例:
    class Subscription(models.Model):
        account_number = models.CharField(db_index=True)
        
        def get_customers(self):
            return Customer.objects.filter(account_number=self.account_number)
        
        @classmethod
        def get_related_customers(cls, subscription_qs):
            return Customer.objects.filter(account_number__in=subscription_qs.values("account_number"))
    

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.30 09:39:03