Я использую 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)
, но это приводит к ошибке "Не удается разрешить ключевое слово" article "в поле. Возможные варианты: ошибка 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'