webentwicklung-frage-antwort-db.com.de

Wählen Sie DISTINCT einzelne Spalten in Django?

Ich bin gespannt, ob es eine Möglichkeit gibt, eine Abfrage in Django das ist kein "SELECT * FROM... "drunter. Ich versuche ein" SELECT DISTINCT columnName FROM ..." stattdessen.

Konkret habe ich ein Modell, das so aussieht:

class ProductOrder(models.Model):
   Product  = models.CharField(max_length=20, promary_key=True)
   Category = models.CharField(max_length=30)
   Rank = models.IntegerField()

wobei Rank ein Rang innerhalb eines Category ist. Ich möchte in der Lage sein, über alle Kategorien zu iterieren, die eine Operation für jeden Rang innerhalb dieser Kategorie ausführen.

Ich möchte zuerst eine Liste aller Kategorien im System abrufen und dann nach allen Produkten in dieser Kategorie suchen und wiederholen, bis alle Kategorien verarbeitet wurden.

Ich würde lieber rohes SQL vermeiden, aber wenn ich dorthin muss, wäre das in Ordnung. Obwohl ich noch nie zuvor in Django/Python rohes SQL codiert habe.

80
jamida

Eine Möglichkeit, die Liste der unterschiedlichen Spaltennamen aus der Datenbank abzurufen, besteht darin, distinct() in Verbindung mit values() zu verwenden.

In Ihrem Fall können Sie folgendermaßen vorgehen, um die Namen verschiedener Kategorien abzurufen:

q = ProductOrder.objects.values('Category').distinct()
print q.query # See for yourself.

# The query would look something like
# SELECT DISTINCT "app_productorder"."category" FROM "app_productorder"

Hier sind einige Dinge zu beachten. Zunächst wird ein ValuesQuerySet zurückgegeben, das sich anders verhält als ein QuerySet. Wenn Sie auf say zugreifen, erhalten Sie als erstes Element von q (oben) ein dictionary, NICHT eine Instanz von ProductOrder.

Zweitens wäre es eine gute Idee, das Warnhinweis in den Dokumenten über die Verwendung von distinct() zu lesen. Das obige Beispiel funktioniert, aber möglicherweise nicht alle Kombinationen von distinct() und values().

[~ # ~] ps [~ # ~] : es ist eine gute Idee, Namen in Kleinbuchstaben für Felder in einem Modell. In Ihrem Fall würde dies bedeuten, dass Sie Ihr Modell wie folgt umschreiben:

class ProductOrder(models.Model):
    product  = models.CharField(max_length=20, primary_key=True)
    category = models.CharField(max_length=30)
    rank = models.IntegerField()
166
Manoj Govindan

Es ist eigentlich ganz einfach wenn Sie PostgreSQL verwenden, verwenden Sie einfach distinct(columns).

Productorder.objects.all().distinct('category')

Beachten Sie, dass diese Funktion seit 1.4 in Django enthalten ist

44
Wolph

Die anderen Antworten sind in Ordnung, aber dies ist ein wenig sauberer, da nur die Werte angezeigt werden, die Sie von einer DISTINCT-Abfrage erhalten würden, ohne dass ein Cruft von Django vorliegt.

>>> set(ProductOrder.objects.values_list('category', flat=True))
{u'category1', u'category2', u'category3', u'category4'}

oder

>>> list(set(ProductOrder.objects.values_list('category', flat=True)))
[u'category1', u'category2', u'category3', u'category4']

Und es funktioniert ohne PostgreSQL.

Dies ist weniger effizient als die Verwendung von .distinct (), vorausgesetzt, DISTINCT in Ihrer Datenbank ist schneller als ein python set, eignet sich jedoch hervorragend zum Nudeln in der Shell.

15
Mark Chackerian

Mit diesem Feld ordnen Sie die Benutzer nach, und führen Sie dann die Unterscheidung durch.

ProductOrder.objects.order_by('category').values_list('category', flat=True).distinct()
7
SuperNova