Как устранить ошибку запроса Django «У объекта« ExtractHour »нет атрибута« split »? - PullRequest
2 голосов
/ 04 мая 2019

Я использую 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)

Ответы [ 3 ]

0 голосов
/ 10 мая 2019

AS @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'))

Gook luck!

0 голосов
/ 11 мая 2019

Используйте OuterRef внутри ExtractHour:


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
    ),
)
0 голосов
/ 04 мая 2019

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=<b>hour_filter</b>)

Так что вам не нужно OuterRef Вот.Как указано в документации на OuterRef:

Используйте OuterRef, когда набор запросов в Subquery должен ссылаться наполе из внешнего запроса .Он действует как выражение F, за исключением того, что проверка того, ссылается ли оно на допустимое поле, не выполняется до тех пор, пока не будет разрешен внешний набор запросов.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...