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

Django查询用户发文关联分类的实现与性能优化

Django ORM优化:高效获取用户文章关联的去重分类

现有实现的性能缺陷

当前写法存在两个明显的性能问题:

  • 产生N+1查询:首先执行1次SQL拉取用户所有文章的分类ID到Python内存,再对每个去重后的分类ID单独执行1次查询获取分类对象,分类数量越多,查询次数越多。
  • 不必要的内存开销:查询分类ID时会拉取所有重复值(比如用户10篇文章都属于同一个分类,会返回10个重复ID),再在Python层转集合去重,当用户发布文章量很大时,会占用多余内存。

优化实现

直接通过Category模型做反向关联查询,在数据库层完成去重,仅需1条SQL即可拿到全部需要的分类对象,完全避免Python层去重和N+1问题,修改get_context_data方法如下:

def get_context_data(self, *args, **kwargs):
    context = super().get_context_data(*args, **kwargs)
    c_form = CommentModelForm(self.request.POST or None)
    target_username = self.kwargs.get('username')
    # 数据库层直接去重查询关联分类,无额外循环查询
    users_categories = Category.objects.filter(
        post__author__username=target_username
    ).distinct()
    context['users_categories'] = users_categories
    return context

实现原理

  • 利用Django ORM跨关联查询的能力,直接筛选出「被目标用户发布的文章关联」的分类条目,调用distinct()时会在生成的SQL中加上DISTINCT关键字,由数据库完成去重,不需要把原始重复数据拉到应用层处理。
  • 该写法天然排除了category=None的空值场景,因为空分类不会在Category表中有对应记录,不需要额外加exclude判断。
  • 对应生成的SQL参考:
SELECT DISTINCT blog_category.*
FROM blog_category
INNER JOIN blog_post ON blog_category.id = blog_post.category_id
INNER JOIN auth_user ON blog_post.author_id = auth_user.id
WHERE auth_user.username = '传入的用户名参数'

可选附加优化

如果模板中需要遍历文章列表访问每篇文章的分类、作者字段,可以在原有get_queryset方法中加上select_related预加载外键关联对象,避免遍历文章时产生额外的外键查询:

def get_queryset(self):
    return (
        super()
        .get_queryset()
        .filter(author__username=self.kwargs.get('username')).order_by('-date_posted')
        # 预加载外键关联对象,消除遍历文章时的外键查询
        .select_related('category', 'author')
        .prefetch_related(
            Prefetch(
                "comment_set",
                queryset=Comment.objects.annotate(
                    like_count=Count("liked")
                ).order_by("-like_count"),
                to_attr="comment_list",
            )
        )
    )

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 19:45:58