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

如何在Django中按模板统计去重后的用户使用次数?

Django统计模板被不同用户使用次数的正确姿势

问题场景

模型结构简化为:

class Post(models.Model):
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    template_id = models.IntegerField(null=True)
    ...

要实现的是:统计每个模板被多少不同用户使用——同一用户哪怕多次用同一个模板,也只算1次。

之前尝试的常规统计代码会重复计数:

counts = Post.objects.all().values("template_id").order_by().annotate(count=Count("template_id"))

虽然用values("template_id", "user__id").distinct()能拿到唯一的用户-模板配对,但在此基础上再统计时,distinct的效果就没了,返回的count还是3(对应测试用例里的3条Post记录):

# 错误写法,结果不符合预期
Post.objects.all().values("template_id", "user__id").distinct().values("template_id").annotate(count=Count("template_id"))

测试用例:

user1 = baker.make("User")
user2 = baker.make("User")

# 填充数据:user1两次用模板1,user2一次用模板1
quest1 = baker.make("post.Post", user=user1, template_id=1)
quest2 = baker.make("post.Post", user=user1, template_id=1)
quest3 = baker.make("post.Post", user=user2, template_id=1)

预期结果是模板1被2位用户使用,但错误代码返回的是3。


正确解法

直接在Count里加distinct=True参数,统计去重后的用户ID:

counts = Post.objects.values("template_id").annotate(
    user_count=Count("user__id", distinct=True)
).order_by()

这样查询后,就能得到每个模板对应的唯一用户数,测试用例里会返回{'template_id': 1, 'user_count': 2},完全符合需求。


为啥之前的写法不行?

你之前的链式调用里,第二次values("template_id")会重置分组依据,相当于抛弃了之前distinct()得到的唯一配对,重新从原始Post表按template_id分组统计数量,自然会把同一用户的多次使用算进去。

如果偏好分步写,也可以先拿到去重的用户-模板对,再统计:

unique_user_template = Post.objects.values("template_id", "user__id").distinct()
counts = unique_user_template.values("template_id").annotate(user_count=Count("user__id"))

不过这种写法不如直接用Count(distinct=True)高效,毕竟少了一次子查询。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.14 08:50:27