Аннотирование специфических атрибутов поля времени даты - Не удается преобразовать ключевое слово 'toordinal' в поле. Объединение по 'created_at' не разрешено
Я разрабатываю систему оценки постов на сайте. Она учитывает другие реляционные поля (комментарии, просмотры и реакции_эмоджи), чтобы иметь более глубокий способ упорядочивания результатов.
Но поскольку нежелательно иметь на первой странице популярные, но слишком старые посты, я решил учитывать время создания поста.
Проблема в том, что значение DateTime слишком точное, и упорядочивание по нему полностью игнорирует систему оценок и возвращает простую хронологическую ленту.
В процессе тестирования некоторых решений, я попробовал встроенную функцию toordinal, чтобы иметь одно значение, представляющее дни, прошедшие с 1 января 1-го года. Моя идея заключалась в конкатенации этого значения с post_hour и результатом (post_minute // 14). Таким образом, в течение 14 минут все посты будут упорядочены исключительно по их оценкам. Это выглядит достаточно хорошо, и любые корректировки будут просты для внесения.
Посмотрев некоторые посты SO и документацию Django, я обнаружил, что могу сделать это, передав атрибут, к которому я пытался получить доступ, с помощью дундера внутри выражения F:
posts = Post.objects.all().annotate(
score=((F("view_count")/20) + (Count("post_emojis")/10) + (Count("post_comments")/5)),
ordinal_time=(F('created_at__toordinal'))
)
Выдает следующую ошибку:
Cannot resolve keyword 'toordinal' into field. Join on 'created_at' not permitted.
Это первый раз, когда я использую annotate, поэтому я немного запутался.
РЕДИТ: Понял! Я опубликую это как ответ после дополнительного тестирования и уверенности, что это не слишком замедлит выполнение запросов.
posts = Post.objects.all().annotate(
score=((F("view_count")/20) + (Count("post_emojis")/10) + (Count("post_comments")/5)),
year=(Extract(expression="created_at", lookup_name='year')),
month=(Extract(expression="created_at", lookup_name='month')),
day=(Extract(expression="created_at", lookup_name='day')),
hour=(Extract(expression="created_at", lookup_name='hour')),
minute=(Extract(expression="created_at", lookup_name='minute')),
divided_minute=(Cast((F("minute") / 14), output_field=IntegerField())),
time=Concat("year", "month", "day", "hour", "divided_minute")
)