Django'da DISTINCT bağımsız sütunları seçin.


100

Django'da SELECT * FROM...altında " " olmayan bir sorgu yapmanın bir yolu olup olmadığını merak ediyorum . Onun SELECT DISTINCT columnName FROM ...yerine " " yapmaya çalışıyorum .

Özellikle şöyle görünen bir modelim var:

class ProductOrder(models.Model):
   Product  = models.CharField(max_length=20, promary_key=True)
   Category = models.CharField(max_length=30)
   Rank = models.IntegerField()

burada Rankbir Category. Bu kategorideki her bir sıralamada bazı işlemler yaparak tüm Kategoriler üzerinde yineleme yapabilmek istiyorum.

Önce sistemdeki tüm kategorilerin bir listesini almak ve ardından o kategorideki tüm ürünleri sorgulamak ve her kategori işlenene kadar tekrarlamak istiyorum.

Ham SQL'den kaçınmayı tercih ederim, ancak oraya gitmem gerekirse, bu iyi olur. Daha önce Django / Python'da ham SQL'i hiç kodlamamıştım.

Yanıtlar:


201

Veritabanından farklı sütun adlarının listesini almanın bir yolu distinct() , ile birlikte kullanmaktır values().

Sizin durumunuzda, farklı kategorilerin adlarını almak için aşağıdakileri yapabilirsiniz:

q = ProductOrder.objects.values('Category').distinct()
print q.query # See for yourself.

# The query would look something like
# SELECT DISTINCT "app_productorder"."category" FROM "app_productorder"

Burada hatırlanması gereken birkaç şey var. İlk olarak, bu, ValuesQuerySeta'dan farklı davranan a'yı döndürecektir QuerySet. Örneğin, q(yukarıdaki) öğesinin ilk öğesine eriştiğinizde, bir sözlüğü alacaksınız ,ProductOrder .

İkincisi, kullanımla ilgili belgelerdeki uyarı notunu okumak iyi bir fikir olacaktır distinct(). Yukarıdaki örnek işe yarayacaktır ancak tüm kombinasyonları distinct()vevalues() olmayabilir.

Not : Bir modeldeki alanlar için küçük harfli isimler kullanmak iyi bir fikirdir . Sizin durumunuzda bu, modelinizi aşağıda gösterildiği gibi yeniden yazmak anlamına gelir:

class ProductOrder(models.Model):
    product  = models.CharField(max_length=20, primary_key=True)
    category = models.CharField(max_length=30)
    rank = models.IntegerField()

1
Aşağıda açıklanan yöntem şu anda django 1.4'te mevcuttur ve alan farkındalığına sahip ProductOrder örneğine ihtiyacınız varsa
iyidir

66

PostgreSQL kullanıyorsanız oldukça basit , sadece distinct(columns)( dokümantasyon ) kullanın .

Productorder.objects.all().distinct('category')

Bu özelliğin Django'ya 1.4'ten beri dahil edildiğini unutmayın.


@lazerscience, @Manoj Govindan: Üzgünüm, haklısınız. Görünüşe göre bu özelliği eklemek için Django'ya yama uyguladım.
Yamaya

3
Bu şimdi Django SVN'de ve Django 1.4'te olacak
Will Hardy

14
Not: PostgreSQL kullanmıyorsanız, ayırt edici () bir argüman veremezsiniz. Yukarıda kabul edilen çözüme en iyi bağlılık
Mark Chackerian

testlerde, bu can_distinct_on_fieldsyalnızca Postgres için görünüyor
Skylar Saveland

4
artı 1, ancak all()burada gerekli değil
Antony Hatchkins

18

Diğer yanıtlar gayet iyi, ancak bu biraz daha net, çünkü Django'dan herhangi bir kesinti olmadan DISTINCT sorgusundan alacağınız değerleri veriyor.

>>> set(ProductOrder.objects.values_list('category', flat=True))
{u'category1', u'category2', u'category3', u'category4'}

veya

>>> list(set(ProductOrder.objects.values_list('category', flat=True)))
[u'category1', u'category2', u'category3', u'category4']

Ve PostgreSQL olmadan da çalışır.

Veritabanınızdaki DISTINCT'in bir python'dan daha hızlı olduğunu varsayarsak, .distinct () kullanmaktan daha az etkilidir set, ancak kabuğun etrafında dolaşmak için harikadır.


values_listkoymuyor DISTINCTolsaydı bu birden çok değer getirecek, böylece sql sorgusunda.
mehmet

1
Bu performans açısından korkunç bir fikir!
boatcoder

1
evet - küçük olmayan bir masanız varsa bunu üretimde yapmayın!
Mark Chackerian

13

Kullanıcı bu alana göre sipariş verin ve ardından farklı yapın.

ProductOrder.objects.order_by('category').values_list('category', flat=True).distinct()
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.