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

Django ORM如何关联子查询实现Join操作统计书籍点赞点踩数量

实现方案

你可以通过以下几种方式实现需求,按适配性和性能排序:

方案1:直接使用原生SQL查询(性能最优,完全匹配你需要的SQL结构)

如果要100%复用你编写的SQL,直接使用Django的raw()方法即可,返回的结果依然是Book模型实例,额外携带n_like和n_dislike属性:

books = Book.objects.raw("""
SELECT b.*, r.n_like, r.n_dislike
FROM book b
JOIN (
  SELECT
    book_id,
    COALESCE(SUM(CASE WHEN outcome='like' THEN 1 ELSE 0 END), 0) n_like,
    COALESCE(SUM(CASE WHEN outcome='dislike' THEN 1 ELSE 0 END), 0) n_dislike
  FROM reaction
  GROUP BY book_id) r ON b.id=r.book_id
""")

方案2:使用ORM聚合语法(纯ORM,Django 2.0+支持)

使用聚合函数的filter参数简化写法,生成的SQL执行效率和你给出的语句几乎一致,适合不想写原生SQL的场景:

from django.db.models import Sum, Q, Coalesce

books = Book.objects.filter(
    # 过滤仅保留有反馈的书籍,等价于INNER JOIN
    reaction__isnull=False
).annotate(
    n_like=Coalesce(Sum(1, filter=Q(reaction__outcome='like')), 0),
    n_dislike=Coalesce(Sum(1, filter=Q(reaction__outcome='dislike')), 0)
).distinct()

方案3:基于你编写的子查询改造

如果你要复用已经写好的子查询逻辑,可以通过OuterRef关联Book主键,分别注解两个统计字段:

from django.db.models import OuterRef, Subquery, IntegerField, Coalesce, Case, When, Sum

# 点赞统计子查询
n_like_sub = Subquery(
    Reaction.objects.filter(book_id=OuterRef('pk'))
    .values('book_id')
    .annotate(cnt=Coalesce(Sum(Case(When(outcome='like', then=1), default=0, output_field=IntegerField())), 0))
    .values('cnt'),
    output_field=IntegerField()
)
# 点踩统计子查询
n_dislike_sub = Subquery(
    Reaction.objects.filter(book_id=OuterRef('pk'))
    .values('book_id')
    .annotate(cnt=Coalesce(Sum(Case(When(outcome='dislike', then=1), default=0, output_field=IntegerField())), 0))
    .values('cnt'),
    output_field=IntegerField()
)

# 最终查询
books = Book.objects.filter(
    pk__in=Reaction.objects.values_list('book_id', flat=True)
).annotate(
    n_like = n_like_sub,
    n_dislike = n_dislike_sub
)

注意:Django原生ORM目前没有直接支持将自定义子查询作为JOIN表的语法,以上三种方案都可以实现你的需求,优先推荐方案1和方案2。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.03 10:57:05