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

Tortoise ORM如何按ManyToManyField关联项数量实现过滤查询

问题原因

Tortoise-ORM 中直接对 ManyToMany 多对多字段、ReverseRelation 反向关联字段添加过滤条件时,ORM默认会去匹配关联模型本身的字段属性,不会自动统计关联条目的总数量,因此原代码中likes__gt=0、comments__gt=0的写法无法生效,会抛出字段不存在的错误。

实现方案

核心逻辑是通过annotate()结合ORM内置的聚合函数,先为每个帖子对象计算出点赞数、评论数的统计字段,再基于这两个生成的统计字段完成过滤、排序操作。

  1. 先导入需要的依赖
from tortoise.functions import Count
from datetime import datetime, timedelta
  1. 编写查询逻辑
# 提前计算7天前的时间阈值,避免重复运算
week_ago = datetime.now() - timedelta(days=7)

posts = Post.annotate(
    # 统计关联点赞总数,distinct=True用于去重,避免联表产生的笛卡尔积导致计数不准
    likes_count=Count("likes", distinct=True),
    # 统计关联评论总数
    comments_count=Count("comments", distinct=True)
).filter(
    likes_count__gt=0,
    comments_count__gt=0,
    created_at__gt=week_ago,
    filter__lte=user.config.filter
)
# 按热门规则排序,示例为优先按点赞数降序、再按评论数降序,可根据业务调整
.order_by("-likes_count", "-comments_count")
优化参考
  • 如果需要自定义热门评分规则(比如设置点赞、评论的不同权重),可以用RawSQL自定义聚合计算字段,参考写法:
from tortoise.expressions import RawSQL

posts = Post.annotate(
    likes_count=Count("likes", distinct=True),
    comments_count=Count("comments", distinct=True),
    # 示例规则:1次点赞计2分,1次评论计3分,按总分排序
    hot_score=RawSQL("COUNT(DISTINCT like_user.user_id)*2 + COUNT(DISTINCT comment.id)*3")
).filter(
    likes_count__gt=0,
    comments_count__gt=0,
    created_at__gt=week_ago,
    filter__lte=user.config.filter
).order_by("-hot_score")
  • 数据量较大时,建议为created_at字段、点赞关联表/评论表的外键字段添加数据库索引,大幅降低联表聚合查询的耗时。
  • 如果需要分页返回热门内容,直接在查询链末尾追加.offset(skip).limit(limit)即可,聚合统计会在分页前完成计算,不会出现计数错误。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.29 05:24:23