Wählen Sie aus einem Tabellenfeld unterschiedliche Werte aus

104

Ich habe Mühe, mich im ORM des Django zurechtzufinden. Ich möchte eine Liste mit unterschiedlichen Werten in einem Feld in meiner Tabelle abrufen. Dies entspricht einem der folgenden Werte:

SELECT DISTINCT myfieldname FROM mytable

(oder alternativ)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Ich würde es zumindest gerne auf Django-Art machen, bevor ich auf rohes SQL zurückgreife. Zum Beispiel mit einer Tabelle:

ID, Straße, Stadt

1, Hauptstraße, Rumpf

2, andere Straße, Rumpf

3, Bibble Way, Leicester

4, ein anderer Weg, Leicester

5, High Street, Londidium

Ich würde gerne bekommen:

Rumpf, Leicester, Londidium.

alj
quelle

Antworten:

202

Angenommen, Ihr Modell ist "Shop".

class Shop(models.Model):
    street = models.CharField(max_length=150)
    city = models.CharField(max_length=150)

    # some of your models may have explicit ordering
    class Meta:
        ordering = ('city')

Da Sie möglicherweise das MetaKlassenattribut orderingfestgelegt haben, können Sie es order_by()ohne Parameter verwenden, um die Reihenfolge bei der Verwendung zu löschen distinct(). Siehe die Dokumentation unter order_by()

Wenn Sie nicht möchten, dass eine Reihenfolge auf eine Abfrage angewendet wird, auch nicht die Standardreihenfolge, rufen Sie order_by () ohne Parameter auf.

und distinct()in der Notiz, in der Probleme bei der Verwendung distinct()bei der Bestellung besprochen werden .

Um Ihre Datenbank abzufragen, müssen Sie nur Folgendes aufrufen:

models.Shop.objects.order_by().values('city').distinct()

Es gibt ein Wörterbuch zurück

oder

models.Shop.objects.order_by().values_list('city').distinct()

Dieser gibt a zurück, ValuesListQuerySetdas Sie in a umwandeln können list. Sie können auch hinzufügen , flat=Trueum values_listdie Ergebnisse zu glätten.

Siehe auch: Unterschiedliche Werte von Queryset nach Feld abrufen

Jujule
quelle
29
Eigentlich funktioniert das. Jedoch! Ich konnte es nicht bei allen meinen Modellen zum Laufen bringen. Weidly, es funktionierte bei einigen, aber nicht bei anderen. Für diejenigen, die eine Meta-Bestellung haben, funktioniert es nicht. Sie müssen also zuerst die Bestellung auf dem Abfragesatz löschen. models.Shop.objects.order_by (). values ​​('city').
unique
2
Es ist wichtig zu beachten, dass values_listeine Liste nicht zurückgegeben wird. Es gibt so etwas wie ein Abfragesatz zurück. Ich fand es nützlich, list () immer um values_list-Aufrufe zu verwenden.
Dheerosaurier
8
values_listGibt ValuesListQuerySet zurück, das ein Iterator ist. Das Casting in eine Liste kann nützlich sein, kann aber auch die Leistung beeinträchtigen, wenn alle Zeilen gleichzeitig ausgewertet werden müssen, insbesondere bei großen Datenmengen.
Peter Kilczuk
3
Das Meta: ordering = ()"Merkmal" von Django Orm und objects.distinct()vs. objects.ordering().distinct()verursachte uns stundenlange Verwirrung. Auf diesem Produkt sollte ein Warnaufkleber für die Verbrauchersicherheit angebracht sein;) Wir können eine Richtlinie für Nicht-Meta-Bestellattribute einführen, um künftig das Kratzen des Kopfes zu verhindern.
Kochfelder
Sie können die MetaKlasse orderingdeaktivieren und Probleme mit lösen, distinctindem Sie order_by()ohne Parameter verwenden. Es befindet sich in den QuerySet-API-Dokumenten unter order_by()" Wenn Sie nicht möchten, dass eine Reihenfolge auf eine Abfrage angewendet wird, nicht einmal die Standardreihenfolge, rufen Sie order_by()ohne Parameter auf. "
Mark Mikofski
11

Neben der immer noch sehr relevanten Antwort von jujule finde ich es sehr wichtig, sich auch der Auswirkungen order_by()auf distinct("field_name")Anfragen bewusst zu sein . Dies ist jedoch nur eine Postgres-Funktion!

Wenn Sie Postgres verwenden und einen Feldnamen definieren, für den die Abfrage eindeutig sein soll, order_by()muss mit demselben Feldnamen (oder denselben Feldnamen) in derselben Reihenfolge begonnen werden (möglicherweise sind danach weitere Felder vorhanden).

Hinweis

Wenn Sie Feldnamen angeben, müssen Sie im QuerySet ein order_by () angeben, und die Felder in order_by () müssen mit den Feldern in different () in derselben Reihenfolge beginnen.

Mit SELECT DISTINCT ON (a) erhalten Sie beispielsweise die erste Zeile für jeden Wert in Spalte a. Wenn Sie keine Reihenfolge angeben, erhalten Sie eine beliebige Zeile.

Wenn Sie z. B. eine Liste von Städten extrahieren möchten, in denen Sie Geschäfte kennen, müsste das Beispiel für Jujule daran angepasst werden:

# returns an iterable Queryset of cities.
models.Shop.objects.order_by('city').values_list('city', flat=True).distinct('city')  
ingofreyer
quelle
2

Zum Beispiel:

# select distinct code from Platform where id in ( select platform__id from Build where product=p)
pl_ids = Build.objects.values('platform__id').filter(product=p)
platforms = Platform.objects.values_list('code', flat=True).filter(id__in=pl_ids).distinct('code')
platforms = list(platforms) if platforms else []
Roger Sodré
quelle