gpt4 book ai didi

python - 如何在 Django 查询集中使用条件注释 Count

转载 作者:IT老高 更新时间:2023-10-28 20:33:46 26 4
gpt4 key购买 nike

使用 Django ORM,可以执行类似 queryset.objects.annotate(Count('queryset_objects', gte=VALUE)) 的操作。 catch 我的漂移?


这里有一个简单的例子来说明一个可能的答案:

在 Django 网站中,内容创建者提交文章,普通用户查看(即阅读)所述文章。文章既可以发表(即可供所有人阅读),也可以以草稿模式发表。描述这些要求的模型是:

class Article(models.Model):
author = models.ForeignKey(User)
published = models.BooleanField(default=False)

class Readership(models.Model):
reader = models.ForeignKey(User)
which_article = models.ForeignKey(Article)
what_time = models.DateTimeField(auto_now_add=True)

我的问题是:我怎样才能获得所有已发表的文章,按过去 30 分钟内的独特读者群排序? IE。我想计算每篇已发表文章在过去半小时内获得了多少不同(唯一)浏览量,然后生成按这些不同浏览量排序的文章列表。


我试过了:

date = datetime.now()-timedelta(minutes=30)
articles = Article.objects.filter(published=True).extra(select = {
"views" : """
SELECT COUNT(*)
FROM myapp_readership
JOIN myapp_article on myapp_readership.which_article_id = myapp_article.id
WHERE myapp_readership.reader_id = myapp_user.id
AND myapp_readership.what_time > %s """ % date,
}).order_by("-views")

这引发了错误:“01”或附近的语法错误(其中“01”是额外内部的日期时间对象)。没什么可继续的。

最佳答案

对于 django >= 1.8

使用 Conditional Aggregation :

from django.db.models import Count, Case, When, IntegerField
Article.objects.annotate(
numviews=Count(Case(
When(readership__what_time__lt=treshold, then=1),
output_field=IntegerField(),
))
)

解释:通过您的文章进行的正常查询将使用 numviews 字段进行注释。该字段将被构造为 CASE/WHEN 表达式,由 Count 包装,它将返回 1 表示读者群匹配条件,NULL 表示读者群不匹配条件。 Count 将忽略空值并仅计算值。

您将在最近未查看的文章中获得零分,您可以使用该 numviews 字段进行排序和过滤。

PostgreSQL 后面的查询将是:

SELECT
"app_article"."id",
"app_article"."author",
"app_article"."published",
COUNT(
CASE WHEN "app_readership"."what_time" < 2015-11-18 11:04:00.000000+01:00 THEN 1
ELSE NULL END
) as "numviews"
FROM "app_article" LEFT OUTER JOIN "app_readership"
ON ("app_article"."id" = "app_readership"."which_article_id")
GROUP BY "app_article"."id", "app_article"."author", "app_article"."published"

如果我们只想跟踪唯一的查询,我们可以在 Count 中添加区分,并使我们的 When 子句返回值,我们想要区分。

from django.db.models import Count, Case, When, CharField, F
Article.objects.annotate(
numviews=Count(Case(
When(readership__what_time__lt=treshold, then=F('readership__reader')), # it can be also `readership__reader_id`, it doesn't matter
output_field=CharField(),
), distinct=True)
)

这将产生:

SELECT
"app_article"."id",
"app_article"."author",
"app_article"."published",
COUNT(
DISTINCT CASE WHEN "app_readership"."what_time" < 2015-11-18 11:04:00.000000+01:00 THEN "app_readership"."reader_id"
ELSE NULL END
) as "numviews"
FROM "app_article" LEFT OUTER JOIN "app_readership"
ON ("app_article"."id" = "app_readership"."which_article_id")
GROUP BY "app_article"."id", "app_article"."author", "app_article"."published"

对于 django < 1.8 和 PostgreSQL

您可以只使用 raw 来执行由较新版本的 django 创建的 SQL 语句。显然,不使用 raw 就没有简单且优化的方法来查询该数据(即使使用 extra 注入(inject)所需的 JOIN 子句也存在一些问题) .

Articles.objects.raw('SELECT'
' "app_article"."id",'
' "app_article"."author",'
' "app_article"."published",'
' COUNT('
' DISTINCT CASE WHEN "app_readership"."what_time" < 2015-11-18 11:04:00.000000+01:00 THEN "app_readership"."reader_id"'
' ELSE NULL END'
' ) as "numviews"'
'FROM "app_article" LEFT OUTER JOIN "app_readership"'
' ON ("app_article"."id" = "app_readership"."which_article_id")'
'GROUP BY "app_article"."id", "app_article"."author", "app_article"."published"')

关于python - 如何在 Django 查询集中使用条件注释 Count,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33775011/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com