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

如何通过单Queryset获取FeedCategory关联的Source及对应Posts?

解决方案:单查询获取FeedCategory及关联Source的Posts

为什么select_related无法获取Posts

select_related仅适用于正向一对一/外键关联的预取,而Post是Source的反向多对一关联(通过related_name='posts'定义),所以无法通过select_related直接获取Posts数据。


方法一:用prefetch_related预取完整Post对象

这是最常用的方案,能一次性拉取所有关联数据,避免N+1查询,且保留完整的Post对象属性。

后端查询代码

from django.db.models import Prefetch

# 预取FeedCategory关联的Source,以及每个Source对应的Posts
feeds = FeedCategory.objects.select_related('source').prefetch_related(
    Prefetch('source__posts', queryset=Post.objects.all())
).all()

如果需要对Posts做筛选(比如只取最新的10篇),可以在Prefetch里指定查询条件:

Prefetch('source__posts', queryset=Post.objects.order_by('-created_at')[:10])

前端模板遍历

注意:模板里的关联字段是feed.source.posts(因为Source的反向关联related_name设为了posts,不是默认的source_set)

{% for feed in feeds %} 
   {{ feed.feed_category }}
   {% for post in feed.source.posts %}
       {{ post.body }}
   {% endfor %}
{% endfor %}

方法二:用annotate聚合Post字段(适合仅需部分字段)

如果不需要完整的Post对象,只需要提取Post的特定字段(比如body),可以用聚合函数将字段集合注入到FeedCategory结果中。

适用于PostgreSQL(支持ArrayAgg)

from django.db.models import ArrayAgg

feeds = FeedCategory.objects.select_related('source').annotate(
    # 将对应Source下所有Post的body聚合为列表
    post_bodies=ArrayAgg('source__posts__body')
).all()

适用于MySQL(用GroupConcat)

MySQL不支持ArrayAgg,需要自定义聚合函数实现字符串拼接:

from django.db.models import Func, Value

class GroupConcat(Func):
    function = 'GROUP_CONCAT'
    template = '%(function)s(%(expressions)s SEPARATOR %(separator)s)'

    def __init__(self, expression, separator=',', **extra):
        super().__init__(
            expression,
            separator=Value(separator),
            **extra
        )

feeds = FeedCategory.objects.select_related('source').annotate(
    post_bodies=GroupConcat('source__posts__body')
).all()

模板使用方式

PostgreSQL直接遍历列表,MySQL需要分割字符串:

{% for feed in feeds %} 
   {{ feed.feed_category }}
   {% for body in feed.post_bodies %}
       {{ body }}
   {% endfor %}
{% endfor %}

(MySQL场景下,把feed.post_bodies改成feed.post_bodies.split(','))


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 15:53:26