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

Django REST Framework中PostgreSQL Words模型结果聚合方案咨询

解决Django Words模型按单词聚合的高效方案

嘿,我完全懂你的困扰——查询含指定关键词的单词时结果重复,想要整理成按单词归类、附带对应时间戳等信息的JSON格式,又不想大改数据库模型,更不想搞一堆冗余的数据库查询对吧?这里给你两个更优雅的实现方案:

方案一:利用PostgreSQL聚合函数(性能最优)

既然你用的是PostgreSQL,可以直接借助它的json_build_object和ArrayAgg函数,在数据库层面一次性完成聚合,全程只需要一次数据库查询,完全避免N+1问题,也不用改动现有模型。

步骤1:定义自定义聚合函数

先封装PostgreSQL的json_build_object为Django可调用的函数:

from django.db.models import Func, Value
from django.contrib.postgres.fields import JSONField

class JSONBuildObject(Func):
    function = 'json_build_object'
    output_field = JSONField()

步骤2:构建聚合查询

过滤出含关键词的单词,按word分组,同时聚合对应的id、lesson和time_stamp为指定格式的数组:

from django.db.models import F
from django.contrib.postgres.aggregates import ArrayAgg

# 替换成你的搜索关键词
target_keyword = "foo"

aggregated_result = Words.objects.filter(word__icontains=target_keyword) \
    .values('word')  # 按word分组
    .annotate(
        list=ArrayAgg(
            JSONBuildObject(
                Value('id'), F('id'),
                Value('lesson'), F('lesson_id'),
                Value('time_stamp'), F('time_stamp')
            )
        )
    ) \
    .order_by('word')

步骤3:返回JSON

直接将查询结果转为JSON响应即可:

from django.http import JsonResponse

return JsonResponse(list(aggregated_result), safe=False)

这个方案的核心是把聚合逻辑交给数据库处理,性能拉满,而且完全符合你想要的输出格式。

方案二:Python层面分组(兼容多数据库)

如果需要兼容非PostgreSQL的数据库,或者更倾向于在应用层控制逻辑,可以先批量查询数据,再在Python内存中完成分组,同时通过select_related避免关联查询的N+1问题。

步骤1:批量查询并预加载关联数据

target_keyword = "foo"

# 用select_related提前加载lesson,避免后续查询lesson时的额外数据库请求
words_queryset = Words.objects.filter(word__icontains=target_keyword).select_related('lesson')

步骤2:Python内存中分组

用collections.defaultdict来快速分组:

from collections import defaultdict

grouped_data = defaultdict(list)
for word_item in words_queryset:
    grouped_data[word_item.word].append({
        "id": word_item.id,
        "lesson": word_item.lesson_id,
        "time_stamp": str(word_item.time_stamp)
    })

# 转成目标格式
final_result = [{"word": word, "list": items} for word, items in grouped_data.items()]

步骤3:返回JSON

return JsonResponse(final_result, safe=False)

这个方案只需要一次数据库查询(因为select_related把lesson表join进来了),代码直观易维护,对数据库没有特殊要求。

方案对比

  • 方案一:性能最优,数据库层面聚合,但依赖PostgreSQL特性;
  • 方案二:兼容性强,代码灵活,适合多数据库场景,性能也足够优秀。

这两个方案都不需要重构现有模型,也不会产生大量数据库查询,完美解决你的痛点~

内容的提问来源于stack exchange,提问作者Dr. Slump

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.09 10:32:30