Я использовал models.py для статических таблиц в django, но эти таблицы динамические. Я не смогу добавлять models.py каждый раз для каждой таблицы.
У меня есть аннотация следующего вида: которая отображает подсчет по месяцам для поля
bar = Foo.objects.annotate(
item_count=Count('item')
).order_by('-item_month', '-item_year')
и это дает результат, подобный этому: html render
Я хотел бы показать изменение item_count по сравнению с item_count предыдущего месяца для каждого месяца (кроме первого). Как я могу добиться этого с помощью аннотаций или мне нужно использовать pandas?
Спасибо
Для этих типов запросов необходимо использовать функции Window в django Orm
Для Лага вы можете воспользоваться помощью
https://docs.djangoproject.com/en/4.0/ref/models/database-functions/#lag
Рабочий запрос в Orm будет выглядеть следующим образом :
#models.py
class Review(models.Model):
user = models.ForeignKey(User, on_delete=models.CASCADE, related_name='review_user', db_index=True)
review_text = models.TextField(max_length=5000)
rating = models.SmallIntegerField(
validators=[
MaxValueValidator(10),
MinValueValidator(1),
],
)
date_added = models.DateTimeField(db_index=True)
review_id = models.AutoField(primary_key=True, db_index=True)
Это просто фиктивная таблица, чтобы показать вам случай использования функций Lag и Window в django.
Потому что примеры для функции Lag не доступны в Django Docs.
from django.db.models.functions import Lag, ExtractYear
from django.db.models import F, Window
print(Review.objects.filter().annotate(
num_likes=Count('likereview_review')
).annotate(item_count_lag=Window(expression=Lag(expression=F('num_likes')),order_by=ExtractYear('date_added').asc())).order_by('-num_likes').distinct().query)
Запрос будет выглядеть как
SELECT DISTINCT `temp_view_review`.`user_id`, `temp_view_review`.`review_text`, `temp_view_review`.`rating`, `temp_view_review`.`date_added`, `temp_view_review`.`review_id`, COUNT(`temp_view_likereview`.`id`) AS `num_likes`, LAG(COUNT(`temp_view_likereview`.`id`), 1) OVER (ORDER BY EXTRACT(YEAR FROM `temp_view_review`.`date_added`) ASC) AS `item_count_lag` FROM `temp_view_review` LEFT OUTER JOIN `temp_view_likereview` ON (`temp_view_review`.`review_id` = `temp_view_likereview`.`review_id`) GROUP BY `temp_view_review`.`review_id` ORDER BY `num_likes` DESC
Также, если вы не хотите упорядочивать_by по извлеченному году даты, вы можете использовать F выражения, подобные этому
print(Review.objects.filter().annotate(
num_likes=Count('likereview_review')
).annotate(item_count_lag=Window(expression=Lag(expression=F('num_likes')),order_by=[F('date_added')])).order_by('-num_likes').distinct().query)
Запрос для этого :
SELECT DISTINCT `temp_view_review`.`user_id`, `temp_view_review`.`review_text`, `temp_view_review`.`rating`, `temp_view_review`.`date_added`, `temp_view_review`.`review_id`, COUNT(`temp_view_likereview`.`id`) AS `num_likes`, LAG(COUNT(`temp_view_likereview`.`id`), 1) OVER (ORDER BY `temp_view_review`.`date_added`) AS `item_count_lag` FROM `temp_view_review` LEFT OUTER JOIN `temp_view_likereview` ON (`temp_view_review`.`review_id` = `temp_view_likereview`.`review_id`) GROUP BY `temp_view_review`.`review_id` ORDER BY `num_likes` DESC