Seleziona valori distinti da un campo della tabella


104

Faccio fatica a capire l'ORM di Django. Quello che voglio fare è ottenere un elenco di valori distinti all'interno di un campo sulla mia tabella ... l'equivalente di uno dei seguenti:

SELECT DISTINCT myfieldname FROM mytable

(o in alternativa)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Mi piacerebbe almeno farlo nel modo Django prima di ricorrere a sql grezzo. Ad esempio, con una tabella:

id, street, city

1, Main Street, Hull

2, altra strada, scafo

3, Bibble Way, Leicester

4, Another Way, Leicester

5, High Street, Londidium

Mi piacerebbe ottenere:

Scafo, Leicester, Londidium.

Risposte:


202

Supponi che il tuo modello sia "Acquista"

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')

Poiché potresti avere impostato l'attributo di Metaclasse ordering, puoi usare order_by()senza parametri per cancellare qualsiasi ordine quando usi distinct(). Vedi la documentazione sotto order_by()

Se non vuoi applicare alcun ordine a una query, nemmeno l'ordinamento predefinito, chiama order_by () senza parametri.

e distinct()nella nota in cui discute i problemi con l'utilizzo distinct()con l'ordinamento.

Per interrogare il tuo DB, devi solo chiamare:

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

Restituisce un dizionario

o

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

Questo restituisce un ValuesListQuerySetche puoi trasmettere a un list. Puoi anche aggiungere flat=Truea values_listper appiattire i risultati.

Vedi anche: Ottieni valori distinti di Queryset per campo


29
In realtà funziona. Però! Non sono riuscito a farlo funzionare su tutti i miei modelli. Weidly, ha funzionato su alcuni ma non su altri. Per quelli che hanno un Meta ordering non funziona. Quindi, devi prima cancellare l'ordinamento sul set di query. models.Shop.objects.order_by (). values ​​('city'). separate ()
alj

2
È importante notare che in values_listrealtà non restituisce un elenco. Restituisce qualcosa come un set di query. Ho trovato utile usare sempre list () intorno alle chiamate values_list.
dheerosaur

8
values_listrestituisce ValuesListQuerySet che è un iteratore. Il cast in elenco potrebbe essere utile, ma può anche migliorare le prestazioni quando tutte le righe devono essere valutate contemporaneamente, soprattutto con set di dati di grandi dimensioni.
Peter Kilczuk,

3
La Meta: ordering = ()"caratteristica" di django orm e objects.distinct()vs. objects.ordering().distinct()ci ha causato ore di confusione. Dovrebbe esserci un adesivo di avvertenza per la sicurezza del consumatore su quel prodotto;) Potremmo istituire una politica senza attributi di meta-ordinazione per prevenire il graffio alla testa in futuro.
piani cottura

Puoi disattivare la Metaclasse orderinge risolvere i problemi con distinctutilizzando order_by()senza parametri. Si trova nella documentazione dell'API QuerySet in order_by()" Se non si desidera applicare alcun ordine a una query, nemmeno l'ordinamento predefinito, chiamare order_by()senza parametri " .
Mark Mikofski

11

Oltre alla risposta ancora molto pertinente di jujule , trovo abbastanza importante anche essere consapevoli delle implicazioni order_by()sulle distinct("field_name")domande. Questa è, tuttavia, una funzionalità unica di Postgres!

Se utilizzi Postgres e definisci un nome di campo per il quale la query deve essere distinta, è order_by()necessario che inizi con lo stesso nome di campo (o nomi di campo) nella stessa sequenza (potrebbero esserci più campi in seguito).

Nota

Quando si specificano i nomi dei campi, è necessario fornire un order_by () nel QuerySet, ei campi in order_by () devono iniziare con i campi distinti (), nello stesso ordine.

Ad esempio, SELECT DISTINCT ON (a) fornisce la prima riga per ogni valore nella colonna a. Se non specifichi un ordine, otterrai una riga arbitraria.

Se vuoi, ad esempio, estrarre un elenco di città in cui conosci i negozi, l'esempio di jujule dovrebbe essere adattato a questo:

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

2

Per esempio:

# 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 []
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.