【问题标题】:Getting count of one column after a distinct on two columns在两列不同之后获取一列的计数
【发布时间】:2022-12-06 08:05:50
【问题描述】:

这是我的模型的简化表示:

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

我想要做的是显示用户使用模板的次数。所以当我列出模板时,我希望能够说Used by X users。主要的吸引力是我不想只计算一个用户一次(所以如果一个用户两次使用一个模板,他们仍然算作“一个用例”)。所有 stackoverflow 帖子都在谈论做这样的事情:

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

但这显然重复计算了两次使用同一模板的用户。我能够像这样在template_iduser 配对上做一个不同的:

Post.objects.all().values("template_id", "user__id").distinct()
# Printing this out, I get 2 distinct entries in the QuerySet:
# <QuerySet [{'template_id': 1, 'user__id': 1}, {'template_id': 1, 'user__id': 2}]>

但是,当我尝试获取 template_id 的计数(下面的代码)时,它似乎忽略了 distinct 并且仍然重复计算用户。

Post.objects.all().values("template_id", "user__id").distinct().values("template_id").annotate(count=Count("template_id"))
# Printing this out I get `count` = 3, which double counts a user.
# <QuerySet [{'template_id': 1, 'count': 3}]>

对于它的价值,我写了一个快速测试用例,它是失败的。

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

# Populate posts
quest1 = baker.make("post.Post", user=user1, template_id=1)
quest2 = baker.make("post.Post", user=user1, template_id=1)  # Duplicate shouldn't count
quest3 = baker.make("post.Post", user=user2, template_id=1)

【问题讨论】:

  • values 后跟 annotate 做一个分组,你应该只使用 count method
  • @AbdulAzizBarkat 所以这里的问题是我在产品中有数百/数千个模板。执行此操作的唯一方法是实际遍历每个模板并手动获取每个模板的计数吗?有没有更有效的方法来做到这一点?
  • 该模板看起来像一个单独的实体,为什么 template_id 是一个整数字段而不是外键?如果您有一个单独的模板模型和适当的外键等,您可能可以从该模型中查询。您可以尝试使用 distinct argumentCount 也许这有帮助?
  • 是的,它绝对应该是另一个模型。我是几年前创建的,所以我的模型并不是设计得最好的。我有一个非常大的 json,其中包含所有模板。我很快就会将其转换为 Django 模型。我试一试不同的论点!
  • distinct in count 不起作用。它为每个模板 ID 提供了 1 个计数。

标签: django


【解决方案1】:

通过执行以下操作,使用 Django 的内置 ORM 使其工作:

        template_ids = []  # My templates

        # Get the number of times each template_id was used.
        top_template_counts = (
            Post.objects.filter(template_id__in=template_ids)
            .values("template_id")  # groups by template ids
            .annotate(user_count=Count("user", distinct=True))  # Gets the number of users using each template
            .order_by("-user_count")
        )

        # Accessing `top_template_counts` 
        for template_id_count in top_template_counts[:10]:
            template_id = template_id_count["template_id"]
            count = template_id_count["parent_count"]

【讨论】:

    【解决方案2】:

    为什么你不使用:

    counts = Post.objects.all().values("template_id", "user__id").distinct().values("template_id").count()
    

    【讨论】:

    • 这给了我正在使用的模板 ID 的数量,而不是次数每个模板都被使用
    • 兄弟,您自己拥有 template_id,因此您可以轻松地使用 filter(template_id=template_id) 而不是使用 .all() 然后您就可以一直使用模板……只需将 all() 更改为 filter(template_id= template_id) 和 values("template_id", "user__id") 到 values("user__id")
    猜你喜欢
    • 2020-03-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-25
    • 1970-01-01
    • 1970-01-01
    • 2011-10-03
    • 1970-01-01
    相关资源
    最近更新 更多