python - 如何编写带有子查询的 Django 查询作为 WHERE 子句的一部分?
问题描述
我正在使用 Django 和 Python 3.7。我无法弄清楚如何编写一个 Django 查询,其中有一个子查询作为 where 子句的一部分。这是模型...
class Article(models.Model):
objects = ArticleManager()
title = models.TextField(default='', null=False)
created_on = models.DateTimeField(auto_now_add=True)
class ArticleStat(models.Model):
objects = ArticleStatManager()
article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
elapsed_time_in_seconds = models.IntegerField(default=0, null=False)
votes = models.FloatField(default=0, null=False)
class StatByHour(models.Model):
index = models.FloatField(default=0)
# this tracks the hour when the article came out
hour_of_day = IntegerField(
null=False,
validators=[
MaxValueValidator(23),
MinValueValidator(0)
]
)
在 PostGres 中,查询看起来类似于
SELECT *
FROM article a,
articlestat ast
WHERE a.id = ast.article_id
AND ast.votes > 100 * (
SELECT "index"
FROM statbyhour
WHERE hour_of_day = extract(hour from (a.created_on + 1000 * interval '1 second')))
注意子查询是 WHERE 子句的一部分
ast.votes > 100 * (select index from statbyhour where hour_of_day = extract(hour from (a.created_on + 1000 * interval '1 second')))
所以我想我可以做这样的事情......
hour_filter = Func(
Func(
(F("article__created_on") + avg_fp_time_in_seconds * "interval '1 second'"),
function='HOUR FROM'),
function='EXTRACT')
...
votes_criterion2 = Q(votes__gte=F("article__website__stats__total_score") / F(
"article__website__stats__num_articles") * settings.TRENDING_PCT_FLOOR *
StatByHour.objects.get(hour_of_day=hour_filter) * day_of_week_index)
qset = ArticleStat.objects.filter(votes_criterion1 & votes_criterion2,
comments__lte=25)
但这会导致“无法将关键字‘文章’解析为字段。选项有:hour_of_day、id、index、num_articles、total_score”错误。我认为这是因为 Django 在运行其中的较大查询之前正在评估我的“StatByHour.objects”查询,但我不知道如何重写以使子查询同时运行。
编辑: K,将我的子查询移动到一个实际的“子查询”函数中,并引用了我使用 OuterRef 创建的过滤器......
hour_filter = Func(
Func(
(F("article__created_on") + avg_fp_time_in_seconds * "interval '1 second'"),
function='HOUR FROM'),
function='EXTRACT')
query = StatByHour.objects.get(hour_of_day=OuterRef(hour_filter))
...
votes_criterion2 = Q(votes__gte=F("article__website__stats__total_score") / F(
"article__website__stats__num_articles") * settings.TRENDING_PCT_FLOOR *
Subquery(query) *
day_of_week_index)
qset = ArticleStat.objects.filter(votes_criterion1 & votes_criterion2,
comments__lte=25)
这导致
This queryset contains a reference to an outer query and may only be used in a subquery.
这很奇怪,因为我在子查询中使用它。
编辑#2:即使在根据给出的答案更改查询之后......
hour_filter = Func(
Func(
(F("article__created_on") + avg_fp_time_in_seconds * "interval '1 second'"),
function='HOUR FROM'),
function='EXTRACT')
query = StatByHour.objects.filter(hour_of_day=OuterRef(hour_filter))[:1]
...
votes_criterion2 = Q(votes__gte=F("article__website__stats__total_score") / F(
"article__website__stats__num_articles") * settings.TRENDING_PCT_FLOOR *
Subquery(query) *
day_of_week_index)
qset = ArticleStat.objects.filter(et_criterion1 & et_criterion2 & et_criterion3,
votes_criterion1 & votes_criterion2,
article__front_page_first_appeared_date__isnull=True,
comments__lte=25)
我仍然收到错误
'Func' object has no attribute 'split'
解决方案
子查询需要是不立即评估的查询,以便它们的评估可以推迟到运行外部查询。get()
不符合要求,因为它会立即执行并返回一个对象实例而不是一个Queryset
.
filter
但是,替换get
然后取[:1]
一片应该可以:
StatByHour.objects.filter(hour_of_day=OuterRef('hour_filter')).values('hour_of_day')[:1]
注意OuterRef中的字段引用是字符串文字而不是变量。
此外,子查询需要返回单列和单行(因为它们被分配给单个字段),因此values()
上面的切片。
另外,我还没有在Q
对象中使用子查询;我不确定它会起作用。您可能必须先将子查询输出保存在注释中,然后将其用于过滤器计算。
推荐阅读
- arrays - 无法初始化十六进制数字数组:“关键字未命名类型”
- security - 显示明文时检索加密值
- javascript - 有没有办法远程测试本机反应?
- shopify - 我的 Liquid 语法是错误的,还是缺少参考?
- python - 使用正则表达式搜索和删除两个标记之间的字符串
- angular - 使用 Jest 进行 ng 测试失败,并在 npm 包上显示 objValue.concat
- python - 减少组合生成脚本的执行时间
- apache-flink - 如何在 Flink keyBy 中使用 lambda 函数
- alexa - 如果在相同的意图中获得不同的插槽值,我可以做出不同的回答吗,AWS Alexa
- java - 以非编程方式将 XML 转换为 Java 类的 IDE 工具