2009-02-13 4 views
5

Ich versuche, eine Ansicht zu schreiben, die einen Bericht generiert, der alle Elemente in meinem Inventory-System anzeigt und Zusammenfassungen an einem bestimmten Punkt bereitstellt. Dieser Bericht ist übrigens nur eine HTML-Vorlage.Generieren von Listen/Berichten mit Inline-Zusammenfassungen in Django

In meinem Fall ist jeder Artikel Teil eines Auftrags. Eine Bestellung kann mehrere Artikel enthalten, und ich möchte SUM-basierte Zusammenfassungen nach dem Ende jeder Bestellung anzeigen können.

So der Bericht sieht irgendwie aus wie folgt aus:

Order #25  <Qty> <Qty Sold> <Cost> <Cost Value> 
Some Item   2  1  29.99 29.99 
Another Item  4  0  10.00 40.00 
<Subtotal Line> 6  1  39.99 69.99 
Order #26  <Qty> <Qty Sold> <Cost> <Cost Value> 
... Etc, you get the point 

Nun, ich bin durchaus in der Lage, alle Werte anzuzeigen und haben bereits einen Bericht alle Artikel zeigt, aber ich habe keine Ahnung, wie kann ich Platzieren Sie Zwischensummen innerhalb des Berichts so, ohne viel von Abfragen. Die Felder Menge, Anzahl verkauft und Kosten sind nur ein Teil des Artikelmodells und Kostenwert ist nur eine einfache Modellfunktion.

Jede Hilfe wäre willkommen. Vielen Dank im Voraus :-)

Antwort

3

Zwischensummen sind SELECT SUM(qty) GROUP BY order_number Dinge.

Sie sind völlig unabhängig von einer Abfrage, um Details zu erhalten.

Die Ergebnisse der beiden Abfragen müssen verschachtelt werden. Ein guter Weg, dies zu tun ist, jede Bestellung als Tupel zu erstellen (list_of_details, appropriate summary).

Dann ist das Display leicht

{% for order in orderList %} 
    {% for line in order.0 %} 
     {{ line }} 
    {% endfor %} 
    {{ order.1 }} 
{% endfor %} 

Der schwierige Teil der beiden Abfragen wird die Verschachtelung.

details = Line.objects.all() 
ddict = defaultdict(list) 
for d in details: 
    ddict[d.order_number].append(d) 

interleaved= [] 
subtotals = ... Django query to get subtotals ... 
for s in subtotals: 
    interleaved.append((ddict[s.order], s.totals)) 

Dieses interleaved Objekt kann für das Rendern zu Ihrer Vorlage gegeben werden.

+0

Vielen Dank! Nachdem ich ein wenig mit dem Django ORM herumgespielt habe, um die richtige GROUP BY-Funktionalität zu erhalten, habe ich es ziemlich gut funktioniert. Danke noch einmal – Bartek

1

Sie könnten die Zwischensummen in Python in der Django-Ansicht berechnen.

Die Zwischensummen können in Instanzen des Model-Objekts mit einem Attribut gespeichert werden, das angibt, dass es sich um eine Zwischensumme handelt. Um die Berichtsvorlage einfach zu halten, können Sie die untergeordneten Objekte an den richtigen Stellen in der Ergebnisliste einfügen und das untergeordnete Attribut verwenden, um die untergeordneten Zeilen anders darzustellen.

+0

Sie sagen also im Grunde durch die erstellte 'report' queryset über Python, und wenn es erkennt, dass ich bei einer neuen Reihenfolge bin, summiere ich die Werte dieser Gruppe von Elementen, dann injizieren das Sub-Total-Attribut innerhalb der Liste am richtigen Punkt? Ich hoffe, das macht Sinn, es ist meine beste Idee ab sofort. – Bartek

+0

Konzeptionell, ja. Die tatsächliche Implementierung könnte vermeiden, dass eine neue Reihenfolge erkannt werden muss, indem ein Zwischenergebniswörterbuch oder eine andere Implementierung verwendet wird. –

1

Angenommen, Sie sind keine auftragsspezifische Felder verwenden gehen, könnten Sie einzelne DB Abfrage von einigen Python Berechnungen gefolgt ausführen:

from itertools import groupby 
items = OrderItem.objects.select_related('order').order_by('order').all() # order_by is essential 
items_by_order = dict(groupby(items, lambda x: x.order)) 
for order, items in items_by_order: 
    items_by_order[order]['subtotals'] = ... # calculate subtotals for all needed fields 

Dies wird allgemeineren Ansatz im Vergleich zur Verwendung separeate SQL-Abfrage für die Berechnung Zwischensummen, die die Synchronisierung von WHERE-Klauseln in beiden Abfragen zur Folge haben. Sie können auch eine beliebige Aggregatfunktion verwenden, nicht nur diejenigen, die auf DB-Seite verfügbar sind.