@ brimborium очень хорош (+1 для него), но я просто хочу подробнее рассказать об этом, используя некоторые цифры. Давайте сначала возьмем примитивное назначение:
int a = new Integer(5);
int b = a;
b = b + b;
System.out.println(a); // 5 as expected
System.out.println(b); // 10 as expected
int a = new Integer(5);
1- Первый оператор создает объект Integer значения 5. Затем, назначив его переменной a
, объект Integer будет распакован и сохраняются в a
в качестве примитива.
После создания объекта Integer и перед назначением:
[/g0]
После назначения:
[/g1]
int b = a;
2- Это только что прочитает значение a
, а затем сохранит его в b
.
(Объект Integer теперь имеет право на сбор мусора, но не обязательно собирает мусор в этой точке)
[/g2]
b = b + b;
3- Это дважды читает значение b
, добавляет их вместе и помещает новое значение в b
.
[/g3]
На другая сторона:
SomeObject s1 = new SomeObject("first");
SomeObject s2 = s1;
s2.setText("second");
System.out.println(s1.getText()); // second as UNexpected
System.out.println(s2.getText()); // second as expected
SomeObject s1 = new SomeObject("first");
1- Создает новый экземпляр класса SomeObject
и назначает его ссылке s1
.
[/g4]
SomeObject s2 = s1;
2- Это приведет к тому, что ссылка s2
указывает на объект, на который указывает s1
. [/ g2 1]
[/g5]
s2.setText("second");
3- Когда вы используете сеттеры для ссылки, он будет изменять объект, на который ссылается ссылка.
[/g6]
System.out.println(s1.getText());
System.out.println(s2.getText());
4- Оба должны печатать second
, так как две ссылки s1
и s2
относятся к одному и тому же объекту (как показано в предыдущем рисунок).
Из ответа Димы Кудоша и на основе https://stackoverflow.com/a/5700744/2240489 мне пришлось сделать следующее: я удалил ссылку на PARTITION BY
в sql и заменил с результатом ORDER BY
.
AModel.objects.annotate(
cumsum=Func(
Sum('a_number'),
template='%(expressions)s OVER (ORDER BY %(order_by)s)',
order_by="id"
)
).values('id', 'cumsum').order_by('id', 'cumsum')
Это дает следующий sql:
SELECT "amodel"."id",
SUM("amodel"."a_number")
OVER (ORDER BY id) AS "cumsum"
FROM "amodel"
GROUP BY "amodel"."id"
ORDER BY "amodel"."id" ASC, "cumsum" ASC
Ответ Димы Кудоша не суммировал результаты, но это было сделано выше.
Для справки, начиная с Django 2.0, для достижения этого результата можно использовать функцию Window
:
AModel.objects.annotate(cumsum=Window(Sum('a_number'), order_by=F('id').Asc()))\
.values('id', 'cumsum').order_by('id', 'cumsum')
Вы можете попытаться сделать это с помощью выражения Func .
from django.db.models import Func, Sum
AModel.objects.annotate(cumsum=Func(Sum('a_number'), template='%(expressions)s OVER (PARTITION BY %(partition_by)s)', partition_by='id')).values('id', 'cumsum').order_by('id')
Проверьте
AModel.objects.order_by("id").extra(select={"cumsum":'SELECT SUM(m.a_number) FROM table_name m WHERE m.id <= table_name.id'}).values('id', 'cumsum')
, где table_name
должно быть именем таблицы в базе данных.