QuerySet mit .latest () für jeden Tag

8

Ich habe ein Grundmodell wie:

%Vor%

Ich führe alle 10 Minuten einen Sellerie-Job aus, um ein neues Statistikobjekt zu erstellen.

Die Verwendung von .latest() auf einem QuerySet gibt mir das neueste Stats-Objekt bis heute.

Ich möchte jedoch eine Liste mit einem Statistikobjekt für jeden Tag.

Betrachten Sie Folgendes:

%Vor%

Die QuerySet sollte die letzte für jeden Tag zurückgeben. Im Beispiel der mit 200 und 222 Wachstum.

In SQL würde ich eine Unterabfrage mit dem Max für jeden Tag starten und sie zusammenfügen.

Da ich kein Raw SQL verwenden möchte, gibt es eine Möglichkeit, dies mit dem Django ORM zu tun?

    
Jannis 20.06.2013, 11:55
quelle

4 Antworten

4

Leider gibt es keinen Weg (den ich kenne .. ich sah ziemlich hart aus) um zu vermeiden, irgendeine Art von raw sql zu benutzen, um das zu erreichen, was du tun willst (mit deinem aktuellen Modell; ein anderer Vorschlag) . Aber Sie können die Auswirkung minimieren, indem Sie so wenig rohe SQL schreiben wie möglich. In der Praxis müssen Django-Sites nicht über verschiedene Datenbanken hinweg portierbar sein. Sofern Sie nicht beabsichtigen, diese App anderweitig zu verwenden oder öffentlich zu veröffentlichen, sollten Sie in Ordnung sein.

Das folgende Beispiel ist für SQLite. Sie könnten eine Zuordnung von Datenbanktypen zu date -Funktionen beibehalten, den Treibertyp nachschlagen und die Funktion bei Bedarf durch die richtige ersetzen.

%Vor%

Ich hatte vorher geschrieben, dass dies nur eine einzige Abfrage war, aber ich log - die values_list muss transformiert werden, um nur das max_date für die nachfolgende Abfrage zurückzugeben, was bedeutet, dass die Anweisung ausgeführt wird. Es sind aber nur 2 Anfragen, die deutlich besser wären als eine N + 1 Funktion.

Das nicht-portable Bit ist das:

%Vor%

Die Verwendung von extra ist nicht ideal, aber die rohe SQL ist hier einfach und eignet sich gut für einen datenbanktreiberabhängigen Ersatz. Nur das date(created) muss ersetzt werden. Sie können dies bei Bedarf in eine Methode für einen benutzerdefinierten Manager einbinden, und Sie haben dieses Problem dann erfolgreich an einem einzigen Ort entfernt.

Die andere Option besteht darin, einfach ein DateField zu Ihrem Modell hinzuzufügen, und dann müssen Sie gar kein extra verwenden. Sie würden einfach den values_list -Aufruf durch einen values_list('created_date') ersetzen, den extra vollständig entfernen und ihn einen Tag nennen. Die Kosten sind offensichtlich - mehr Speicherplatz wird benötigt. Es ist auch nicht intuitiv, warum Sie ein Date - und ein DateTime -Feld im selben Modell haben. Wenn Sie beide synchron halten, kann dies ebenfalls Probleme verursachen.

    
Josh Smeaton 23.06.2013, 14:28
quelle
0

Vielleicht können Sie etwas tun, wie:

%Vor%

oder Ähnliches

%Vor%     
Victor Castillo Torres 20.06.2013 16:56
quelle
0

Überlegen Sie sich zusätzlich zu den anderen beiden Antworten, die Ergebnisse in einem anderen Modell zu speichern (insbesondere, wenn sich die Daten pro Tag nach der Eingabe nicht viel ändern und Sie große Datenmengen haben). Etwas wie:

%Vor%

Und füge eine periodische Sellerie-Aufgabe hinzu:

%Vor%

Ergebnisse abrufen mit:

%Vor%

Neben anderen Faktoren, die berücksichtigt werden müssen, stellt dieser Ansatz natürlich das Problem dar, DailyStat zu aktualisieren, wenn sich ein vergangener Status ändert usw. ( Signale können verwendet werden, wenn Sie diesen Pfad verwenden.)

    
stellarchariot 24.06.2013 02:26
quelle
0

TruncDate ist neu in Django & gt; 2.0 und es ist jetzt möglich, dieselbe Abfrage kürzer zu machen, aber nur in Datenbanken mit distinct support wie PostgreSQL.

Stats.objects.all().annotate(date=TruncDay('created')).distinct('created').order_by('-date')

    
YYYY-MM-DD 17.01.2018 16:15
quelle

Tags und Links