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

如何在Django查询中为用户添加最喜爱文章分类统计?

扩展Django查询:获取用户点赞总数及最喜爱文章分类

我来帮你搞定这个需求!下面先梳理下现有基础,再给出两种可行的实现方案——一种是基于你现有raw SQL的扩展,另一种是更符合Django风格的ORM实现。

现有模型结构

首先回顾下你的Django模型(修正了笔误的DateBaseModel):

from django.db import models
class ArticleCategory(models.Model):
    name = models.CharField(('Name'), max_length=255)
class Article(models.Model):
    category = models.ForeignKey('articles.ArticleCategory', null=True, blank=True, related_name='articles', on_delete=models.SET_NULL)
class ArticleLike(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='user_likes')
    article = models.ForeignKey('articles.Article', on_delete=models.CASCADE, related_name='article_likes')

现有查询逻辑

你当前用raw SQL获取用户的点赞总数:

from django.contrib.auth import get_user_model
User = get_user_model()
condition = """
SELECT (
    SELECT COUNT(articles_articlelike.id)
    FROM articles_articlelike
    WHERE articles_articlelike.user_id = account_account.id
) AS "likes_count", "account_account"."id"
FROM "account_account"
"""
users = User.objects.raw(condition)

方案一:扩展原有Raw SQL

我们需要关联点赞记录→文章→分类,统计每个用户各分类的点赞次数,取最高的那个分类的ID和名称。修改后的SQL如下:

SELECT 
    -- 原有点赞总数统计
    (SELECT COUNT(al.id) FROM articles_articlelike al WHERE al.user_id = account_account.id) AS "likes_count",
    -- 获取点赞最多的分类名称(无点赞时返回'无')
    COALESCE(
        (SELECT ac.name 
         FROM articles_articlelike al
         JOIN articles_article a ON al.article_id = a.id
         JOIN articles_articlecategory ac ON a.category_id = ac.id
         WHERE al.user_id = account_account.id
         GROUP BY ac.id, ac.name
         ORDER BY COUNT(al.id) DESC, ac.name ASC  -- 点赞数相同时按分类名排序,保证结果稳定
         LIMIT 1),
        '无'
    ) AS "favorite_category_name",
    -- 获取点赞最多的分类ID(无点赞时返回NULL)
    (SELECT ac.id 
     FROM articles_articlelike al
     JOIN articles_article a ON al.article_id = a.id
     JOIN articles_articlecategory ac ON a.category_id = ac.id
     WHERE al.user_id = account_account.id
     GROUP BY ac.id, ac.name
     ORDER BY COUNT(al.id) DESC, ac.name ASC
     LIMIT 1) AS "favorite_category_id",
    account_account.id
FROM account_account

逻辑说明:

  1. 通过JOIN串联ArticleLike→Article→ArticleCategory,关联用户的点赞记录到对应的分类
  2. 按分类分组统计点赞数,降序排序后取第一条,就是用户点赞最多的分类
  3. 用COALESCE处理无点赞的用户,返回友好的默认值
  4. 额外加上ac.name ASC排序,避免多个分类点赞数相同时结果随机

方案二:用Django ORM实现(更推荐)

如果不想写原生SQL,可以用Django的annotate和Subquery来实现,更符合Django的开发习惯,也能自动适配表名变化:

from django.contrib.auth import get_user_model
from django.db.models import Count, Subquery, OuterRef
from articles.models import ArticleCategory

User = get_user_model()

# 子查询:获取当前用户点赞最多的分类名称
favorite_category_name_subquery = ArticleCategory.objects.filter(
    # 通过反向关联找到用户点赞的文章对应的分类
    articles__article_likes__user=OuterRef('pk')
).annotate(
    # 统计该分类下用户的点赞次数
    like_count=Count('articles__article_likes')
).order_by(
    '-like_count', 'name'  # 按点赞数降序,名称升序
).values('name')[:1]  # 只取第一条

# 子查询:获取当前用户点赞最多的分类ID
favorite_category_id_subquery = ArticleCategory.objects.filter(
    articles__article_likes__user=OuterRef('pk')
).annotate(
    like_count=Count('articles__article_likes')
).order_by(
    '-like_count', 'name'
).values('id')[:1]

# 最终查询:获取用户ID、点赞总数、最喜爱分类
users = User.objects.annotate(
    # 统计用户总点赞数
    likes_count=Count('user_likes'),
    # 关联子查询获取分类信息
    favorite_category_name=Subquery(favorite_category_name_subquery),
    favorite_category_id=Subquery(favorite_category_id_subquery)
).values('id', 'likes_count', 'favorite_category_name', 'favorite_category_id')

优势:

  • 无需硬编码表名,Django会自动处理
  • 代码可读性更强,符合ORM的设计思想
  • 方便后续扩展或修改查询条件

注意事项

  • 如果用户有多个分类点赞数相同且都是最大值,两种方案都会取排序后的第一个(我们加了name ASC来保证结果稳定)
  • 对于没有任何点赞的用户,likes_count会是0,favorite_category_name会是None(SQL方案中我们用COALESCE改成了'无',ORM方案可以在后续处理中补充)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 09:05:58