python - 如何编写带有子查询的 Django 查询作为 WHERE 子句的一部分?

标签 python django python-3.x postgresql subquery

我正在使用 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'

最佳答案

Subqueries需要是不立即评估的查询,以便可以将它们的评估推迟到运行外部查询之前。 get() 不符合要求,因为它会立即执行并返回对象实例而不是 Queryset

但是,将 filter 替换为 get 然后获取 [:1] 切片应该可行:

StatByHour.objects.filter(hour_of_day=OuterRef('hour_filter')).values('hour_of_day')[:1]

请注意 OuterRef 中的字段引用是字符串文字而不是变量。

此外,子查询需要返回单个列和单个行(因为它们被分配给单个字段),因此 values() 和上面的切片。

此外,我还没有在 Q 对象中使用子查询;我不确定它会起作用。您可能必须先将子查询输出保存在注释中,然后将其用于过滤器计算。

关于python - 如何编写带有子查询的 Django 查询作为 WHERE 子句的一部分?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55638498/

相关文章:

python - 如何将矢量场限制在一定半径的圆上?

python - boto3、aiobotocore、awscli 和 botocore 的版本不兼容;无法解决

python - 将 Excel 单元格值直接读取到复杂的 Python 对象,DataNitro

Django 用户模型电子邮件字段 : how to make it mandatory

Django 管理员通过 get_list_filter 在远程字段上进行过滤

python - 按子页面日期排序列表

python - 在 Pandas DataFrame 的字符串中漂亮地打印换行符

python - 通过电子邮件发送图像

c++ - 删除 setup.py 中的所有默认编译器参数

python - 如何在 ‘\n’ 上拆分一行并将拆分后的所有内容添加到新行?