Bir sorgu kümesini sıralamak için iyi yollar? - Django


112

yapmaya çalıştığım şey şudur:

  • en yüksek puana sahip 30 Yazarı al ( Author.objects.order_by('-score')[:30])

  • yazarları sırala last_name


Baska öneri?


4
@RH: Peki AlexMartelli'nin yanıtını doğru çözüm olarak kontrol etmeye ne dersiniz? (Skeet denen adamın peşinden gitmediği sürece daha fazla
tekrara

Yanıtlar:


191

Ne dersin

import operator

auths = Author.objects.order_by('-score')[:30]
ordered = sorted(auths, key=operator.attrgetter('last_name'))

Django 1.4 ve daha yeni sürümlerde, birden çok alan sağlayarak sipariş verebilirsiniz.
Referans: https://docs.djangoproject.com/en/dev/ref/models/querysets/#order-by

order_by (* alanlar)

Varsayılan olarak, a tarafından döndürülen sonuçlar , modelin QuerySetMeta'sındaki orderingseçenek tarafından verilen sıralama dizisine göre sıralanır . order_byYöntemi kullanarak bunu QuerySet başına temelinde geçersiz kılabilirsiniz .

Misal:

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

Yukarıdaki sonuç scoreazalan, sonra last_nameartan şekilde sıralanacaktır . Önündeki eksi işareti "-score"azalan sırayı gösterir. Artan sıra ima edilir.


1
@Alex: grazie alex! Bu harikaydı, operatör modülü hakkında okumaya gidiyorum!
RadiantHex 09

3
Bu, Author.objects.order_by ('- puan', 'son_adı') [: 30] 'dan daha verimli mi?
Brian Luft

4
@Brian - "daha verimli" derken "daha doğru" demek istiyorsan evet, onun. :) Çözümünüz yazarları hemen hemen puana göre sıralı tutar ve yalnızca aynı puana sahip yazarları alfabetik sıralar (ikincil anahtarlar böyle çalışır). Alex, sonuçların nasıl alınacağını ve sonra bunlara tamamen farklı bir sıralama düzeninin nasıl uygulanacağını gösterir (nesne başına anahtar ifadesi tanımlamak için key = operator.attrgetter kullanarak), ki bu OP'nin istediği şeydir.
PaulMcG

@Paul: Yine de sorduğum bu değil, Alex'in cevabı doğru!
RadiantHex

4
Neden sıralama anahtarı işlevini yapmıyorsunuz lambda x: x.last_name? Daha kısa, daha ayrıntılı ve içe aktarmaya gerek yok.
Krzysztof Szularz

12

Sadece yerleşik çözümlerin (yalnızca SQL) her zaman en iyisi olmadığını göstermek istedim. İlk başta, Django'nun QuerySet.objects.order_byyöntemi birden fazla argümanı kabul ettiği için bunları kolayca zincirleyebileceğinizi düşündüm :

ordered_authors = Author.objects.order_by('-score', 'last_name')[:30]

Ancak beklediğiniz gibi çalışmıyor. Örnek olarak, ilk önce puana göre sıralanmış başkanların bir listesidir (daha kolay okumak için ilk 5'i seçin):

>>> auths = Author.objects.order_by('-score')[:5]
>>> for x in auths: print x
... 
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)

Alex Martelli'nin en iyi 5 kişiyi doğru şekilde sıralayan çözümünü kullanarak last_name:

>>> for x in sorted(auths, key=operator.attrgetter('last_name')): print x
... 
Benjamin Harrison (467)
James Monroe (487)
Gerald Rudolph (464)
Ulysses Simpson (474)
Harry Truman (471)

Ve şimdi birleşik order_byçağrı:

>>> myauths = Author.objects.order_by('-score', 'last_name')[:5]
>>> for x in myauths: print x
... 
James Monroe (487)
Ulysses Simpson (474)
Harry Truman (471)
Benjamin Harrison (467)
Gerald Rudolph (464)

Gördüğünüz gibi, birincisi ile aynı sonuç, yani beklediğiniz gibi çalışmıyor.


13
Sonucunuz # 3, puana göre azalan sıralıyor ve ardından son_adına göre IFF tüm nesneler aynı puana sahip. Sorun, sonuç kümenizdeki nesnelerin hiçbirinin aynı puana sahip olmamasıdır, bu nedenle sıralama düzenini yalnızca '-puan' etkiliyor. 3 yazarın puanını 487 olarak ayarlamayı deneyin ve 3 numarayı tekrar çalıştırın.
istruble

Evet anlıyorum. Sadece yerleşik çözümlerin (yalnızca SQL) her zaman en iyisi olmadığını göstermek istedim.
jathanism

3
Tam olarak beklediğim şeyi yaptı: sözlüksel sıralama (ilk sıralama anahtarı tamamen farklıysa bu biraz önemsizdir).
Jonas Kölker

5

İşte kesme puanı için eşitliğe izin veren bir yol.

author_count = Author.objects.count()
cut_off_score = Author.objects.order_by('-score').values_list('score')[min(30, author_count)]
top_authors = Author.objects.filter(score__gte=cut_off_score).order_by('last_name')

Bu şekilde top_authors kategorisinde 30'dan fazla yazar alabilirsiniz ve min(30,author_count)30'dan az yazara sahip olmanız durumunda orada olur.

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.