Класс Window
Класс Window применяется в сочетании с агрегирующими функциями для выполнения вычислений в рамках оконных функций. Он позволяет ранжировать строки, вычислять скользящие средние, накопительные суммы и другие статистические показатели без группировки всего набора данных. Класс принимает параметры для определения порядка сортировки, разбиения на партиции и указания диапазона строк.
Синтаксис
from django.db.models import Window
Window(
expression,
partition_by=None,
order_by=None,
frame=None,
output_field=None,
)
Пример . С ранжированием
Давайте создадим модель для статей с рейтингом и добавим поле с рангом каждой статьи в общем списке:
from django.db import models
from django.db.models import Window, F
from django.db.models.functions import Rank
class Article(models.Model):
title = models.CharField(max_length=100)
rating = models.IntegerField()
# Добавляем ранг для каждой статьи
articles = Article.objects.annotate(
rank=Window(
expression=Rank(),
order_by=F('rating').desc()
)
)
for article in articles:
print(f"{article.title}: rank {article.rank}")
Результат выполнения кода:
"Python Basics: rank 1"
"Django Guide: rank 2"
"Web Development: rank 2"
"JavaScript Tips: rank 4"
Пример . С разбиением на категории
Теперь добавим ранжирование внутри каждой категории, используя параметр partition_by:
from django.db import models
from django.db.models import Window, F
from django.db.models.functions import Rank
class Article(models.Model):
title = models.CharField(max_length=100)
category = models.CharField(max_length=50)
rating = models.IntegerField()
# Ранжируем статьи внутри каждой категории
articles = Article.objects.annotate(
category_rank=Window(
expression=Rank(),
partition_by=F('category'),
order_by=F('rating').desc()
)
)
for article in articles:
print(f"{article.category}: {article.title} - rank {article.category_rank}")
Результат выполнения кода:
"Tech: Python Basics - rank 1"
"Tech: Django Guide - rank 2"
"Tech: Web Development - rank 3"
"Science: Physics 101 - rank 1"
"Science: Chemistry Basics - rank 2"
Пример . С накопительной суммой
Рассмотрим вычисление накопительной суммы в рамках отсортированных данных с использованием Sum и Window:
from django.db import models
from django.db.models import Window, F, Sum
class Sale(models.Model):
product = models.CharField(max_length=100)
date = models.DateField()
amount = models.IntegerField()
# Вычисляем накопительную сумму продаж по датам
sales = Sale.objects.order_by('date').annotate(
cumulative_sum=Window(
expression=Sum('amount'),
order_by=F('date').asc()
)
)
for sale in sales:
print(f"{sale.date}: {sale.amount} (cumulative: {sale.cumulative_sum})")
Результат выполнения кода:
"2026-01-01: 100 (cumulative: 100)"
"2026-01-02: 150 (cumulative: 250)"
"2026-01-03: 200 (cumulative: 450)"
"2026-01-04: 120 (cumulative: 570)"
Пример . С разбиением и накопительной суммой
Комбинируем разбиение на партиции и накопительную сумму для вычисления суммы продаж по каждому продукту отдельно:
from django.db import models
from django.db.models import Window, F, Sum
class Sale(models.Model):
product = models.CharField(max_length=100)
date = models.DateField()
amount = models.IntegerField()
# Накопительная сумма по каждому продукту
sales = Sale.objects.order_by('product', 'date').annotate(
product_cumulative=Window(
expression=Sum('amount'),
partition_by=F('product'),
order_by=F('date').asc()
)
)
for sale in sales:
print(f"{sale.product}: {sale.date} - {sale.amount} (cum: {sale.product_cumulative})")
Результат выполнения кода:
"Laptop: 2026-01-01 - 500 (cum: 500)"
"Laptop: 2026-01-03 - 300 (cum: 800)"
"Laptop: 2026-01-05 - 200 (cum: 1000)"
"Phone: 2026-01-02 - 400 (cum: 400)"
"Phone: 2026-01-04 - 350 (cum: 750)"