Pilih nilai yang berbeda dari bidang tabel

104

Saya berjuang keras agar kepala saya berada di sekitar ORM Django. Yang ingin saya lakukan adalah mendapatkan daftar nilai berbeda dalam bidang di tabel saya .... yang setara dengan salah satu dari berikut ini:

SELECT DISTINCT myfieldname FROM mytable

(atau sebagai alternatif)

SELECT myfieldname FROM mytable GROUP BY myfieldname

Saya setidaknya ingin melakukannya dengan cara Django sebelum beralih ke sql mentah. Misalnya, dengan tabel:

id, jalan, kota

1, Jalan Utama, Hull

2, Jalan Lain, Hull

3, Bibble Way, Leicester

4, Cara Lain, Leicester

5, Jalan Tinggi, Londidium

Saya ingin mendapatkan:

Hull, Leicester, Londidium.

alj
sumber

Jawaban:

202

Katakanlah model Anda adalah 'Belanja'

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

Karena Anda mungkin memiliki kumpulan atribut Metakelas ordering, Anda dapat menggunakan order_by()tanpa parameter untuk menghapus pengurutan apa pun saat menggunakan distinct(). Lihat dokumentasi di bawah order_by()

Jika Anda tidak ingin pengurutan apa pun diterapkan ke kueri, bahkan pengurutan default, panggil order_by () tanpa parameter.

dan distinct()dalam catatan yang membahas masalah penggunaan distinct()dengan pemesanan.

Untuk menanyakan DB Anda, Anda hanya perlu memanggil:

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

Ini mengembalikan kamus

atau

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

Yang ini mengembalikan ValuesListQuerySetyang dapat Anda lemparkan ke list. Anda juga dapat menambahkan flat=Trueke values_listuntuk meratakan hasil.

Lihat juga: Mendapatkan nilai Queryset yang berbeda menurut bidang

jujule
sumber
29
Sebenarnya itu berhasil. Namun! Saya tidak bisa membuatnya berfungsi pada semua model saya. Weidly, itu berhasil pada beberapa tetapi tidak pada yang lain. Bagi mereka yang memiliki pengurutan Meta itu tidak berfungsi. Jadi, Anda harus menghapus urutan di queryset terlebih dahulu. models.Shop.objects.order_by (). values ​​('city']. different ()
alj
2
Penting untuk dicatat bahwa values_listsebenarnya tidak mengembalikan daftar. Ini mengembalikan sesuatu seperti queryset. Saya merasa berguna untuk selalu menggunakan list () di sekitar panggilan values_list.
dheerosaurus
8
values_listmengembalikan ValuesListQuerySet yang merupakan iterator. Mentransmisikan ke daftar mungkin berguna, tetapi juga dapat menghasilkan performa ketika semua baris harus dievaluasi sekaligus, terutama dengan kumpulan data yang besar.
Peter Kilczuk
3
The Meta: ordering = ()"fitur" dari Django orm dan objects.distinct()vs objects.ordering().distinct()menyebabkan kita jam kebingungan. Harus ada stiker peringatan keselamatan konsumen pada produk itu;) Kami dapat menerapkan kebijakan atribut tanpa-Meta-ordering untuk mencegah garuk kepala di masa mendatang.
kompor
Anda dapat menonaktifkan Metakelas orderingdan menyelesaikan masalah dengan distinctmenggunakan order_by()tanpa parameter. Ini ada di dokumen QuerySet API di bawah order_by()" Jika Anda tidak ingin pengurutan apa pun diterapkan ke kueri, bahkan pengurutan default, panggil order_by()tanpa parameter. "
Mark Mikofski
11

Selain masih sangat relevan jawaban dari jujule , saya merasa cukup penting untuk juga menyadari implikasi dari order_by()pada distinct("field_name")permintaan. Namun, ini hanya fitur Postgres!

Jika Anda menggunakan Postgres dan jika Anda menentukan nama bidang yang kueri harusnya berbeda, maka order_by()harus dimulai dengan nama bidang yang sama (atau nama bidang) dalam urutan yang sama (mungkin ada lebih banyak bidang sesudahnya).

Catatan

Saat Anda menentukan nama bidang, Anda harus memberikan order_by () di QuerySet, dan bidang di order_by () harus dimulai dengan bidang di different (), dalam urutan yang sama.

Misalnya, SELECT DISTINCT ON (a) memberi Anda baris pertama untuk setiap nilai di kolom a. Jika Anda tidak menentukan pesanan, Anda akan mendapatkan beberapa baris arbitrer.

Jika Anda ingin misalnya mengekstrak daftar kota yang Anda ketahui berbelanja, contoh jujule harus disesuaikan dengan ini:

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

Contohnya:

# 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é
sumber