【问题标题】:How do I resolve a Django query "'ExtractHour' object has no attribute 'split'" error?如何解决 Django 查询“'ExtractHour' 对象没有属性'split'”错误?
【发布时间】:2019-09-22 22:43:07
【问题描述】:

我正在使用 Django 和 Python 3.7。我想在更大查询的条件中包含一个子查询。

from django.db.models.functions import ExtractHour
...
hour_filter = ExtractHour(ExpressionWrapper(
            F("article__created_on") + timedelta(0, avg_fp_time_in_seconds),
            output_field=models.DateTimeField()
        ),
)
query = StatByHour.objects.filter(hour_of_day=OuterRef(hour_filter))

...

包含它的更大查询是

qset = ArticleStat.objects.filter(                votes__gte=F("article__website__stats__total_score") / F(
                "article__website__stats__num_articles") *
                       Subquery(query.values('index'), outout_field=FloatField()) *
                       day_of_week_index)

但是,当我运行它时,我得到了错误

'ExtractHour' object has no attribute 'split'

这是什么意思以及如何调整过滤器以消除此错误?

编辑:添加进行外部查询的事物的模型...

class ArticleStat(models.Model):
    objects = ArticleStatManager()
    article = models.ForeignKey(Article, on_delete=models.CASCADE, related_name='articlestats')
    ...
    votes = models.FloatField(default=0, null=False)

【问题讨论】:

  • 那么你为什么要把ExtractHour 包裹在OuterRef 中?

标签: python sql django python-3.x model


【解决方案1】:

正如@WillemVanOnsem 指出的那样:

当子查询中的查询集需要引用外部查询中的字段时,请使用 OuterRef。它的作用类似于 F 表达式,只是在解析外部查询集之前不会检查它是否引用了有效字段。

然后你做到了:

query = StatByHour.objects.filter(hour_of_day=OuterRef(hour_filter))

hour_filter 被视为字段查找,而 Django 正在执行一种

hour_filter.split('__')

为了收集预期字段查找的部分。

hour_filter 在这里是ExtractHour,因此出现错误。

您可以尝试使用所需的时间来注释您的文章统计信息,然后处理结果:

 hour_value = ExtractHour(
    ExpressionWrapper(
        F("article__created_on") + timedelta(0, avg_fp_time_in_seconds),
        output_field=models.DateTimeField()
    ),
)


qset = ArticleStat.objects.annotate(
    hour = hour_value
).filter(
     # ... and write your filter based on the annotate field (hour) here.
)

整个事情可能看起来像(我没有对此进行测试,这只是为您指出正确方向的努力):

hour_value = ExtractHour(
    ExpressionWrapper(
        F("article__created_on") + timedelta(0, avg_fp_time_in_seconds),
        output_field=models.DateTimeField()
    ),
)


qset = ArticleStat.objects.annotate(
    hour = hour_value
).filter(
    votes__gte=F("article__website__stats__total_score") / 
               F("article__website__stats__num_articles") *
               F("hour") * day_of_week_index
)

附录:

如果您仍想在此处使用子查询,您可以修改已有的子查询,以使其适用于带注释的字段:

query = StatByHour.objects.filter(hour_of_day=OuterRef('hour'))

祝你好运!

【讨论】:

  • 在您的回答中,您删除了我尝试使用的子查询。 “hour_value”不直接插入到 ArticleStat 查询中,而是插入到直接插入到 ArticleStat 查询中的子查询中。所以你有 "F("hour") * day_of_week_index" 但我想要 "Subquery[that uses hour] * day_of_week_index"。
  • 嘿!在尝试了您在编辑中建议的内容后,它似乎正在工作。哇 taht 难倒我这么久!无论如何,我会再进行一些测试,然后我会回来接受。
【解决方案2】:

ExtractHour 中使用OuterRef


from django.db.models.functions import ExtractHour
...
query = StatByHour.objects.filter(
    hour_of_day=ExtractHour(ExpressionWrapper(
            # NOTE: `OuterRef()+something` works only on Django >= 2.1.0
            OuterRef("article__created_on") + timedelta(0, avg_fp_time_in_seconds),
            output_field=models.DateTimeField()
        ),
    )
)

qset = ArticleStat.objects.filter(
    votes__gte=(
        F("article__website__stats__total_score") 
        / 
        F("article__website__stats__num_articles") 
        *
        Subquery(
            query.values('index')[:1], 
            output_field=FloatField()
        ) 
        *
        day_of_week_index
    ),
)

【讨论】:

    【解决方案3】:

    OuterRef 用于从父查询中获取值,但这里根本不需要来自外部查询的引用。

    from django.db.models.functions import ExtractHour
    
    hour_filter = ExtractHour(
        ExpressionWrapper(
            F('article__created_on') + timedelta(0, avg_fp_time_in_seconds),
            output_field=models.DateTimeField()
        )
    )
    query = StatByHour.objects.filter(hour_of_day=hour_filter)

    所以你在这里不需要OuterRef。正如documentation on OuterRef 所说:

    Subquery 中的查询集需要引用 来自外部查询的字段。它的作用类似于F 表达式,除了 直到检查它是否引用了一个有效字段 外部查询集已解析。

    【讨论】:

    • 谢谢,但我确实需要引用外部查询(ArticleStat 模型)中的一个字段。实际上,当我删除 OuterRef 时,我收到一个错误,“无法将关键字 'article' 解析为字段。选择有:hour_of_day、id、index、num_articles、total_score”,这些都是来自子查询“StatByHour 对象”的所有字段。跨度>
    • @Dave:那么StatByHourArticle 模型之间显然没有关系?您确实需要添加关系,否则 Django 可以通过知道的方式了解您的目标。是否可以显示模型的(相关)部分?
    • "article" 与 ArticleStat 相关,所以这就是我使用 OuterRef 的原因,因为根据您所拥有的,我需要从外部查询中引用一个字段。 StatByHour 和 ArticleStat 之间没有关系。我会尽快添加模型。
    • @Dave: 但正如之前所说的OuterRef 需要一个字符串:它用于获取对外部查询中特定列的引用。
    • 哦,感谢您的澄清,我没有低估这一点。所以我不知道如何进行。我包括了我想要返回的模型,我只是不知道如何写一个字符串。我会写“articlestat.article”之类的吗?
    猜你喜欢
    • 2019-03-15
    • 1970-01-01
    • 2018-10-03
    • 2014-05-15
    • 2022-01-16
    • 1970-01-01
    • 2022-11-29
    • 2019-09-08
    • 2020-10-25
    相关资源
    最近更新 更多