Wie zu verwenden Unterabfrage in django?
Möchte ich, um eine Liste der neuesten Kauf eines jeden Kunden, die nach dem Datum sortiert.
Folgende Abfrage macht, was ich will, außer das Datum:
(Purchase.objects
.all()
.distinct('customer')
.order_by('customer', '-date'))
Erzeugt es eine Abfrage wie:
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
Bin ich gezwungen, zu verwenden customer_id
als die ersten ORDER BY
Ausdruck, weil der DISTINCT ON
.
Möchte ich Sortieren nach dem Datum, also was die Abfrage, die ich wirklich brauchen sollte wie folgt Aussehen:
SELECT * FROM (
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
)
AS result
ORDER BY date DESC;
Ich nicht Sortieren möchten mit python, weil ich immer noch auf Seite beschränken Sie die Abfrage. Es können zig-Tausende von Zeilen in der Datenbank.
In der Tat ist es derzeit sortiert in python nun und führt zu sehr langen Ladezeiten, so dass ist, warum ich bin versucht, dies zu beheben.
Grundsätzlich will ich so etwas https://stackoverflow.com/a/9796104/242969. Ist es möglich, express es mit django querysets statt raw SQL?
Die aktuellen Modelle und Methoden sind mehrere Seiten lang, aber hier ist eine Reihe von Modellen erforderlich, für den queryset oben.
class Customer(models.Model):
user = models.OneToOneField(User)
class Purchase(models.Model):
customer = models.ForeignKey(Customer)
date = models.DateField(auto_now_add=True)
item = models.CharField(max_length=255)
Wenn ich Daten wie:
Customer A -
Purchase(item=Chair, date=January),
Purchase(item=Table, date=February)
Customer B -
Purchase(item=Speakers, date=January),
Purchase(item=Monitor, date=May)
Customer C -
Purchase(item=Laptop, date=March),
Purchase(item=Printer, date=April)
Ich möchte in der Lage sein, zu extrahieren, die folgenden:
Purchase(item=Monitor, date=May)
Purchase(item=Printer, date=April)
Purchase(item=Table, date=February)
Gibt es höchstens einen Kauf in der Liste pro Kunde. Der Kauf ist jeder Kunde das neueste. Es ist sortiert nach dem aktuellen Datum.
Dieser Abfrage werden in der Lage zu extrahieren, die:
SELECT * FROM (
SELECT DISTINCT ON
"shop_purchase.customer_id"
"shop_purchase.id"
"shop_purchase.date"
FROM "shop_purchase"
ORDER BY "shop_purchase.customer_id" ASC,
"shop_purchase.date" DESC;
)
AS result
ORDER BY date DESC;
Ich versuche einen Weg zu finden, nicht zu haben, um mit raw-SQL um dieses Ergebnis zu erreichen.
- Nicht diese Abfrage gibt Ihnen, was erforderlich ist
Purchase.objects.order_by('-date').distinct('customer')
? - Ich kann nicht 🙁
DatabaseError: SELECT DISTINCT ON expressions must match initial ORDER BY expressions
.customer_id
muss die ersteORDER BY
Ausdruck. stackoverflow.com/questions/9795660/... - Raw-SQL? Die Django ORM nervt^H^H^H^H^Seiner nicht sehr flexibel.
- Können Sie erklären, welche Ergebnisse Sie möchten, dass Ihre Abfrage zurückgeben? Außerdem können Sie nach Ihrem Modell-Klassen?
- user27478: ich habe beispielsweise Daten möchte ich kehrte minimal-model-Klasse. Paulo Scardine: Es zeigt, dass die Fehlermeldung auch, wenn Sie ausschließlich verwenden Djangos ORM.
Purchase.objects.all().distinct('customer').order_by('-date')
Diese queryset tun würde. - Sie waren in der Lage, dies zu lösen, mit Django ORM? Wenn ja, bitte teilen Sie Ihre Lösung.
- Es ist eine long-standing akzeptiert neue feature Tickets: code.djangoproject.com/ticket/24218
Du musst angemeldet sein, um einen Kommentar abzugeben.
Dies ist vielleicht nicht genau das, was du suchst, aber vielleicht kommen Sie sich näher. Werfen Sie einen Blick auf Django ' s kommentieren.
Hier ist ein Beispiel für etwas, das vielleicht helfen:
Dadurch erhalten Sie eine Liste Ihrer Kunden Modelle, von denen jedes haben ein neues Attribut namens "most_recent_purchase" und enthält das Datum, an dem Sie Ihren letzten Kauf. Die sql produziert, sieht wie folgt aus:
Andere Möglichkeit wäre das hinzufügen einer Eigenschaft, um Ihre Kunden-Modell würde wie folgt Aussehen:
Würden Sie müssen natürlich auf den Fall behandeln, wo Sie nicht vorhanden sind Käufe in dieser Eigenschaft, und dies würde möglicherweise nicht sehr performant (da müsste man eine Abfrage für jeden Kunden, um Ihre neueste Anschaffung).
Ich habe beides verwendet diese Techniken in der Vergangenheit und Sie haben beide funktionierte gut in verschiedenen Situationen. Ich hoffe, das hilft. Viel Glück!
.extra
. Jedenfalls habe ich beschlossen zu gehen mit so etwas wiePurchase.objects.filter(id__in=purchases).order_by('-date')
, wopurchases
ist die VorherigeDISTINCT ON
queryset. Es werde noch eine Abfrage, aber mitIN
anstelle der weniger effizient ist, aber zumindest bleibt es in einer einzigen Abfrage.Wann immer es ist eine schwierige Abfrage zu schreiben, mit Django ORM, habe ich zunächst versuchen, die Abfrage in psql(oder was auch immer client, den Sie verwenden). Die SQL, die Sie wollen, ist nicht dies:
In der obigen SQL, die SQL innere ist suchen distinct auf eine Kombination von (customer_id, id und Datum) und da die id eindeutig sein für alle, bekommst du alle Datensätze aus der Tabelle. Ich bin vorausgesetzt, id ist der Primärschlüssel als pro-übereinkommen.
Wenn Sie brauchen, um zu finden, dass der Letzte Kauf eines jeden Kunden, müssen Sie etwas tun, wie:
Aber das problem mit der obigen Abfrage ist, dass es wird Ihnen nur der name des Kunden und Datum. Über das wird nicht helfen Ihnen bei der Suche nach Aufzeichnungen, wenn Sie diese Ergebnisse nutzen, die in einer Unterabfrage.
Verwenden
IN
müssen Sie eine Liste von eindeutigen Parametern zur Identifizierung eines Datensatzes, z.B. idWenn in Ihren Unterlagen id ist ein serial-key, dann können Sie nutzen die Tatsache, dass das Letzte Datum wird die maximale id. Damit Ihre SQL wird:
Beachten Sie, dass ich behielt nur ein Feld (id) in der ausgewählten Klausel in einer Unterabfrage mit IN.
Das komplette SQL wird jetzt sein:
und mit der Django-ORM sieht es so aus:
Hoffe, es hilft!
Ich habe eine ähnliche situation und das ist, wie ich bin Planung, um darüber zu gehen:
Kopf es gibt mir die Abfrage, die ich will. Nachteil ist, dass es roh-Abfrage und ich kann es nicht Anhängen, alle anderen queryset-Filter.
Dies ist mein Ansatz, wenn ich einen Teil der Daten (N Elemente) zusammen mit dem Django-Abfrage. Dieses ist zum Beispiel die Verwendung von PostgreSQL und handlich
json_build_object()
Funktion (Postgres 9.4+), aber die gleiche Weise können Sie eine andere Aggregatfunktion in anderen Datenbank-system. Bei älteren PostgreSQL-Versionen können Sie verwenden, Kombination vonarray_agg()
undarray_to_string()
Funktionen.Stellen Sie sich vor Sie haben
Article
undComment
Modelle und zusammen mit jedem Artikel in der Liste, die Sie auswählen möchten, die 3 letzten Kommentare (ändernLIMIT 3
zu passen Sie die Größe der Teilmenge oderORDER BY c.id DESC
ändern die Sortierung der Teilmenge).