Django'da SELECT MAX nasıl yapılır?


91

Bir alanın maksimum değerini vermek için bir sorguyu nasıl çalıştırabileceğim bir nesne listem var:

Bu kodu kullanıyorum:

def get_best_argument(self):
    try:
        arg = self.argument_set.order_by('-rating')[0].details
    except IndexError:
        return 'no posts'
    return arg

derecelendirme bir tam sayıdır

Yanıtlar:


173

Bunu gör . Kodunuz aşağıdaki gibi olacaktır:

from django.db.models import Max
# Generates a "SELECT MAX..." query
Argument.objects.aggregate(Max('rating')) # {'rating__max': 5}

Bunu mevcut sorgu kümelerinde de kullanabilirsiniz:

from django.db.models import Max
args = Argument.objects.filter(name='foo') # or whatever arbitrary queryset
args.aggregate(Max('rating')) # {'rating__max': 5}

Bu maksimum değeri içeren model örneğine ihtiyacınız varsa, gönderdiğiniz kod muhtemelen bunu yapmanın en iyi yoludur:

arg = args.order_by('-rating')[0]

Sorgu kümesi boşsa, yani sorguyla eşleşen hiçbir argüman yoksa (çünkü [0]parça bir yükseltecektir IndexError) bunun hata vereceğini unutmayın . Bu davranıştan kaçınmak ve bunun yerine basitçe Nonebu durumda geri dönmek istiyorsanız , şunu kullanın .first():

arg = args.order_by('-rating').first() # may return None

4
Bu Max'e sahip olan actuall argüman nesnesine ihtiyacım var, böylece ayrıntılar alanını yazdırabilirim. Args.aggregate (Max ('rating')) çağrısı yalnızca en yüksek derecelendirmeyi döndürür. En yüksek reytinge sahip argümanı arıyorum.
Johnd

1
Çıkış kodunuzun nesi var - Argument.objects.order_by ("- rating") [0]?
AdamKG

74

Django ayrıca en son (maksimum değer) girişi bulan ' en yeni (alan_adı = Yok) ' işlevine de sahiptir . Yalnızca tarih alanlarıyla değil aynı zamanda dizeler ve tamsayılarla da çalışır.

Bu işlevi çağırırken alan adını verebilirsiniz:

max_rated_entry = YourModel.objects.latest('rating')
return max_rated_entry.details

Veya model meta verilerinizde bu alan adını zaten verebilirsiniz:

from django.db import models

class YourModel(models.Model):
    #your class definition
    class Meta:
        get_latest_by = 'rating'

Artık herhangi bir parametre olmadan 'en son ()' çağrısı yapabilirsiniz:

max_rated_entry = YourModel.objects.latest()
return max_rated_entry.details

3
Bu, kullanmanın harika bir yoludur latest(). Minimum değeri olan kayda ihtiyacınız varsa kullanabilirsiniz earliest().
SaeX

7
latest()ve earliest()tarih olmayan alanla da çalışır, ancak uygulamanın bir yan etkisidir. Django geliştiricileri değişse ve yalnızca tarih alanlarıyla çalışmak için uygulama yapsa bile kodunuzun çalıştığından emin olmak için <your-queryset>.order_by('<interested-field>').first()veya kullanmalısınız . <your-queryset>.order_by('<interested-field>').last()latest()earliest()
mrnfrancesco

Bu kötü bir cevap: 1) daha önce fark edildiği gibi, uygulamanın ayrıntıları ve gelecekte değiştirilebilir 2) çok okunabilir değil - en son kaydedilen maksimum sayı (veya başka bir anlamda) olmak zorunda değil
Mikhail Gerasimov

47

Bunu projem için test ettim, maks / dakikayı O (n) zamanında bulur:

from django.db.models import Max

# Find the maximum value of the rating and then get the record with that rating. 
# Notice the double underscores in rating__max
max_rating = App.objects.aggregate(Max('rating'))['rating__max']
return App.objects.get(rating=max_rating)

Bu, tüm tabloyu sıralamak ve en tepeyi elde etmek (yaklaşık O (n * logn)) yerine, verimli bir şekilde maksimum öğelerden birini elde etmenizi sağlar.


8
Big-O bazen pratikte, özellikle katsayıların ve uygulamanın önemli olduğu daha küçük n için geçerli değildir. Kodunuz, bayt koduna göre derlenen ve optimize edilebilen veya edilmeyen python / django'da. Veritabanı büyük olasılıkla optimize edilmiş ve makine talimatlarına göre derlenmiş bir dilde yazılmıştır. Ayrıca, işlev yalnızca bir maksimum değer arıyorsa, veritabanının sıralama yapmak için gerçek bir nedeni yoktur. Yerleşik bir veritabanı işlevi üzerinden el yapımı kodu kullanmaya alışmadan önce zamanlama verilerini görmek istiyorum.
benevolentprof

5
@afahim Bu gönderdiğiniz kodun tamamen doğru olduğunu düşünmüyorum. Birden fazla maksimuma sahip olduğunuz ortaya çıkarsa (5 yıldızlı iki Uygulamanız olduğunu varsayalım) "al" seçeneğini kullanmak bir hata oluşturacaktır.
Raydel Miranda
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.