2017-04-20 2 views
3

Ist es möglich, die kumulative (laufende) Summe mit djangos orm zu berechnen? Betrachten Sie das folgende Modell:Kumulative (laufende) Summe mit django orm und postgresql

class AModel(models.Model): 
    a_number = models.IntegerField() 

mit einem Satz von Daten, bei denen a_number = 1. So dass ich eine Nummer (> 1) von AModel Instanzen in der Datenbank alle mit a_number=1 haben. Ich möchte in der Lage sein, die folgenden zurück:

AModel.objects.annotate(cumsum=??).values('id', 'cumsum').order_by('id') 
>>> ({id: 1, cumsum: 1}, {id: 2, cumsum: 2}, ... {id: N, cumsum: N}) 

Im Idealfall würde ich gerne in der Lage sein, die kumulative Summe zu begrenzen/filtern. Also im obigen Fall möchte ich das Ergebnis auf cumsum <= 2

begrenzen Ich glaube, dass in Postgresql kann man eine kumulative Summe mit Fensterfunktionen erreichen. Wie wird dies in das ORM übersetzt?

+0

Ich verstehe es nicht. Was ist Cumsum? Und es gibt nur einen Datensatz mit ID = 1 –

+0

Cumsum == kumulative Summe, offensichtlich ist dies für mehr als einen Datensatz - bearbeitet, um klarer zu machen, so dass die Größe des Datensatzes größer als eins ist. – wrdeman

+0

Ich glaube nicht, dass Sie es mit dem ORM tun können ... verwenden Sie stattdessen Python –

Antwort

2

Von Antwort des Dima Kudosh und basierend auf https://stackoverflow.com/a/5700744/2240489 hatte ich folgende zu tun: in entfernte ich den Verweis auf PARTITION BY im SQL und ersetzt mit ORDER BY resultierenden

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') 

Dieses folgendes gibt. 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 

Dima Kudosh Antwort wurde nicht auf die Ergebnisse summiert aber die oben tut.

0

prüfen diese

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') 

wo table_name sollte der Name der Tabelle in der Datenbank sein.

1

Sie können versuchen, dies mit Func expression zu tun.

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') 
+0

Danke, wirklich deine Antwort zu schätzen. Es hat nicht ganz funktioniert und ich habe meinen Änderungsantrag veröffentlicht. – wrdeman