Wybierz różne wartości z pola tabeli

105

Walczę z poruszaniem się po ORM Django. Chcę uzyskać listę różnych wartości w polu w mojej tabeli ... odpowiednik jednego z poniższych:

SELECT DISTINCT myfieldname FROM mytable

(lub alternatywnie)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Chciałbym przynajmniej zrobić to w sposób Django, zanim skorzystam z surowego sql. Na przykład ze stołem:

id, ulica, miasto

1, Main Street, Hull

2, Inna ulica, Hull

3, Bibble Way, Leicester

4, Inny sposób, Leicester

5, High Street, Londidium

Chciałbym dostać:

Hull, Leicester, Londidium.

alj
źródło

Odpowiedzi:

206

Powiedz, że Twój model to „Sklep”

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

Ponieważ możesz mieć ustawiony atrybut Metaclass ordering, możesz użyć order_by()bez parametrów, aby wyczyścić kolejność podczas używania distinct(). Zobacz dokumentację pod order_by()

Jeśli nie chcesz, aby do zapytania był stosowany żaden porządek, nawet domyślna, wywołaj order_by () bez parametrów.

oraz distinct()w notatce, w której omawia problemy z korzystaniem distinct()z zamawiania.

Aby zapytać o swoją bazę danych, wystarczy zadzwonić:

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

Zwraca słownik

lub

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

Ten zwraca a, ValuesListQuerySetktóry możesz rzucić na plik list. Możesz także dodać flat=Truedo, values_listaby spłaszczyć wyniki.

Zobacz także: Pobieranie różnych wartości Queryset według pola

jujule
źródło
29
Właściwie to działa. Jednak! Nie mogłem zmusić go do działania we wszystkich moich modelach. Weidly działało na niektórych, ale nie na innych. Dla tych, którzy mają Meta zamawianie, to nie działa. Musisz więc najpierw wyczyścić kolejność w zestawie zapytań. models.Shop.objects.order_by (). values ​​('city').
another
2
Należy zauważyć, że w values_listrzeczywistości nie zwraca to listy. Zwraca coś w rodzaju zestawu zapytań. Uważam, że przydatne jest zawsze używanie list () wokół wywołań wartości_list.
dheerosaur
8
values_listzwraca ValuesListQuerySet, który jest iteratorem. Przesyłanie na listę może być przydatne, ale może również wpłynąć na wydajność, gdy wszystkie wiersze muszą zostać ocenione jednocześnie, szczególnie w przypadku dużych zestawów danych.
Peter Kilczuk
3
Meta: ordering = ()„Cecha” Django ORM oraz objects.distinct()vs. objects.ordering().distinct()spowodowane nam godziny zamieszania. Na tym produkcie powinna znajdować się naklejka ostrzegawcza dotycząca bezpieczeństwa konsumenta;) Możemy wprowadzić politykę braku atrybutu meta-zamawiania, aby zapobiec zarysowaniu głowy w przyszłości.
płyty grzewcze
Możesz wyłączyć Metaklasę orderingi rozwiązać problemy z distinctużyciem order_by()bez parametrów. Znajduje się w dokumentacji QuerySet API w sekcji order_by()Jeśli nie chcesz, aby do zapytania zastosowano kolejność, nawet domyślną, wywołaj order_by()bez parametrów.
Mark Mikofski
11

Poza tym nadal bardzo istotnych odpowiedzi na jujule uważam, że to bardzo ważne, aby być także świadomi konsekwencji order_by()na distinct("field_name")zapytaniami. Jest to jednak tylko funkcja Postgres!

Jeśli używasz Postgres i jeśli zdefiniujesz nazwę pola, dla którego zapytanie powinno być odrębne, to order_by()musi zaczynać się tą samą nazwą pola (lub nazwami pól) w tej samej kolejności (później może być więcej pól).

Uwaga

Kiedy określasz nazwy pól, musisz podać order_by () w QuerySet, a pola w order_by () muszą zaczynać się od pól w clear (), w tej samej kolejności.

Na przykład SELECT DISTINCT ON (a) podaje pierwszy wiersz dla każdej wartości w kolumnie a. Jeśli nie określisz zamówienia, otrzymasz dowolny wiersz.

Jeśli chcesz np - wyodrębnić listę miast, w których znasz sklepy, przykład jujule musiałby zostać dostosowany do tego:

# returns an iterable Queryset of cities.
models.Shop.objects.order_by('city').values_list('city', flat=True).distinct('city')  
ingofreyer
źródło
2

Przez przykład:

# 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é
źródło