导读:本期聚焦于小伙伴创作的《如何在 Django 中高效过滤多对多关系中任意关联对象满足条件的记录》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何在 Django 中高效过滤多对多关系中任意关联对象满足条件的记录》有用,将其分享出去将是对创作者最好的鼓励。

在Django的ORM操作中,多对多关系的过滤是高频需求,比如文章模型关联了多个标签,需要筛选出所有关联了标签为Python或者Django的文章,这类需求的核心是判断主模型的关联对象中是否存在任意一个满足条件的情况。如果处理不当,很容易写出低效的查询代码,甚至引发性能问题。

如何在 Django 中高效过滤多对多关系中任意关联对象满足条件的记录

基础模型定义

首先我们定义两个存在多对多关系的模型,后续所有示例都基于这两个模型展开:

from django.db import models

class Tag(models.Model):
    name = models.CharField(max_length=50, verbose_name="标签名称")

    def __str__(self):
        return self.name

class Article(models.Model):
    title = models.CharField(max_length=200, verbose_name="文章标题")
    content = models.TextField(verbose_name="文章内容")
    tags = models.ManyToManyField(Tag, related_name="articles", verbose_name="关联标签")

    def __str__(self):
        return self.title

使用filter直接过滤多对多字段

Django的ORM支持直接通过多对多字段的关联条件进行过滤,当我们需要筛选关联对象中任意一个满足条件时,直接对多对多字段的关联属性加过滤条件即可,ORM会自动处理关联查询的逻辑。

比如我们需要筛选出所有关联了名称为Python的标签的文章,代码如下:

# 筛选关联了标签名为Python的文章
articles = Article.objects.filter(tags__name="Python")

如果需要筛选关联了标签名为Python或者Django的文章,直接添加多个条件即可,ORM会自动处理为OR逻辑:

# 筛选关联了标签名为Python或者Django的文章
articles = Article.objects.filter(tags__name="Python", tags__name="Django")

这里需要注意,同一个filter中的多个条件针对的是同一个关联对象,上述代码实际是筛选同时关联了Python和Django两个标签的文章,如果需要筛选关联任意一个的情况,需要使用Q对象:

from django.db.models import Q

# 筛选关联了Python或者Django标签的文章(任意一个满足即可)
articles = Article.objects.filter(Q(tags__name="Python") | Q(tags__name="Django"))

使用prefetch_related优化查询

如果过滤之后还需要访问文章的关联标签数据,直接使用filter可能会产生额外的查询,这时候可以配合prefetch_related预加载关联数据,避免N加1查询问题。

# 过滤后预加载关联标签,避免后续访问标签时产生额外查询
articles = Article.objects.filter(
    Q(tags__name="Python") | Q(tags__name="Django")
).prefetch_related("tags")

for article in articles:
    # 这里访问tags不会再产生新的数据库查询
    print(f"文章标题:{article.title},关联标签:{[tag.name for tag in article.tags.all()]}")

复杂条件的多对多过滤

如果过滤条件更复杂,比如需要筛选关联标签的创建时间在某个月份之后,或者标签名称包含特定字符,同样可以直接在filter中拼接条件:

import datetime

# 筛选关联了2024年1月之后创建的标签的文章
target_date = datetime.date(2024, 1, 1)
articles = Article.objects.filter(tags__create_time__gte=target_date)

如果需要先对关联对象做过滤再关联到主模型,也可以使用Prefetch对象自定义预加载的查询集:

from django.db.models import Prefetch

# 预加载时只加载名称为Python的标签
prefetch = Prefetch("tags", queryset=Tag.objects.filter(name="Python"))
articles = Article.objects.prefetch_related(prefetch).filter(tags__name="Python")

不同过滤方式性能对比

我们可以通过Django的query属性查看生成的SQL语句,对比不同写法的查询效率:

# 查看直接filter生成的SQL
articles = Article.objects.filter(tags__name="Python")
print(articles.query)

直接filter多对多字段的方式,ORM会生成带INNER JOIN的SQL语句,只查询一次数据库就能得到结果,性能最优。而如果使用先查询所有文章再遍历判断的方式,会产生大量额外的数据库查询,效率极低,不建议在生产环境使用。

注意事项

  • 多对多过滤时,同一个filter中的多个条件默认是AND逻辑,需要OR逻辑时要使用Q对象。
  • 如果过滤后不需要访问关联对象,不需要使用prefetch_related,避免额外的查询开销。
  • 当多对多关系的中间表有额外字段时,过滤逻辑需要通过中间表模型来操作,不能直接通过主模型的多对多字段过滤。
多对多关系的过滤核心是利用Django ORM的关联查询能力,避免手动遍历判断,同时根据是否需要访问关联数据选择是否预加载,就能实现高效的查询逻辑。

Django多对多关系ORM过滤querysetfilter修改时间:2026-07-18 11:30:31

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。