Bir tablo alanından farklı değerler seçin


105

Django'nun ORM'sinde kafamı bulmaya çalışıyorum. Yapmak istediğim şey, tablomdaki bir alanda farklı değerlerin bir listesini almaktır .... aşağıdakilerden birine eşdeğer:

SELECT DISTINCT myfieldname FROM mytable

(Veya alternatif olarak)

SELECT myfieldname FROM mytable GROUP BY myfieldname

En azından ham sql'ye başvurmadan önce Django yöntemiyle yapmak istiyorum. Örneğin, bir masa ile:

id, cadde, şehir

1, Ana Cadde, Gövde

2, Diğer Cadde, Gövde

3, İncil Yolu, Leicester

4, Başka Bir Yol, Leicester

5, Yüksek Sokak, Londidium

Almak istiyorum:

Hull, Leicester, Londidium.

Yanıtlar:


206

Modelinizin 'Mağaza' olduğunu söyleyin

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

MetaSınıf orderingözniteliğine sahip olabileceğinizden , kullanırken order_by()herhangi bir sıralamayı temizlemek için parametresiz kullanabilirsiniz distinct(). () Altındaki belgelere bakınorder_by

Bir sorguya herhangi bir sıralamanın uygulanmasını istemiyorsanız, varsayılan sıralamada bile, parametresiz order_by () öğesini çağırın.

ve siparişle distinct()ilgili kullanım sorunlarını tartıştığı notta distinct().

DB'nizi sorgulamak için aramanız yeterlidir:

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

Bir sözlük döndürür

veya

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

Bu ValuesListQuerySet, bir list. Ayrıca ekleyebilir flat=Trueiçin values_listsonuçlar düzleştirmek için.

Ayrıca bkz: Alana göre Sorgu kümesinin farklı değerlerini alma


29
Aslında işe yarıyor. Ancak! Tüm modellerimde çalışmasını sağlayamadım. Weidly, bazılarında işe yaradı, bazılarında değil. Meta siparişi olanlar için işe yaramıyor. Bu nedenle, önce sorgu kümesindeki sıralamayı temizlemelisiniz. modeller.Shop.objects.order_by (). values ​​('şehir'). farklı ()
alj

2
values_listAslında bir liste döndürmediğini unutmamak önemlidir . Sorgu kümesi gibi bir şey döndürür. Value_list çağrıları etrafında her zaman list () kullanmayı yararlı buldum.
dheerosaur

8
values_listYineleyici olan ValuesListQuerySet'i döndürür. Listeye çevrim kullanışlı olabilir, ancak özellikle büyük veri kümelerinde olmak üzere tüm satırların aynı anda değerlendirilmesi gerektiğinde performans da etkileyebilir.
Peter Kilczuk

3
Meta: ordering = ()Django ORM ve "özelliği" objects.distinct()vs. objects.ordering().distinct()bize karışıklık saat neden oldu. Bu ürün üzerinde bir tüketici güvenliği uyarı etiketi olmalıdır;) Gelecekte başın kaşınmasını önlemek için Meta-sipariş özelliği olmayan bir politika oluşturabiliriz.
Ocak

Hiçbir parametre kullanmadan Metasınıfı kapatabilir orderingve sorunları çözebilirsiniz . QuerySet API belgelerinde, " Bir sorguya herhangi bir sıralamanın uygulanmasını istemiyorsanız, varsayılan sıralamanın bile parametresiz çağırın . "distinctorder_by()order_by()order_by()
Mark Mikofski

11

Jujule'nin hala çok alakalı cevabına ek olarak, sorgular order_by()üzerindeki etkilerinin de farkında olmayı oldukça önemli buluyorum distinct("field_name").Ancak bu, yalnızca bir Postgres özelliğidir!

Postgres kullanıyorsanız ve sorgunun farklı olması gereken bir alan adı tanımlarsanız order_by(), aynı sırayla aynı alan adı (veya alan adları) ile başlamanız gerekir (daha sonra daha fazla alan olabilir).

Not

Alan adlarını belirttiğinizde, QuerySet'te order_by () sağlamanız gerekir ve order_by () içindeki alanlar aynı sırayla farklı () içindeki alanlarla başlamalıdır.

Örneğin, SELECT DISTINCT ON (a) size a sütunundaki her değer için ilk satırı verir. Bir sipariş belirtmezseniz, rastgele bir satır alırsınız.

Örneğin, alışveriş yaptığını bildiğiniz şehirlerin bir listesini çıkarmak istiyorsanız, hünnap örneğinin buna uyarlanması gerekir:

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

2

Örnek olarak:

# 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 []
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.