Как сделать SELECT MAX в Django?

У меня есть список объектов, как я могу запустить запрос, чтобы дать максимальное значение поля:

Я использую этот код:

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

рейтинг - целое число


person Johnd    schedule 10.05.2009    source источник


Ответы (6)


См. это. Ваш код будет примерно таким:

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

Вы также можете использовать это для существующих наборов запросов:

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

Если вам нужен экземпляр модели, содержащий это максимальное значение, то опубликованный вами код, вероятно, является лучшим способом сделать это:

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

Обратите внимание, что это приведет к ошибке, если набор запросов пуст, то есть если ни один аргумент не соответствует запросу (поскольку часть [0] вызовет IndexError). Если вы хотите избежать такого поведения и вместо этого просто вернуть None в этом случае, используйте .first():

arg = args.order_by('-rating').first() # may return None
person Sasha Chedygov    schedule 10.05.2009
comment
Мне нужен фактический объект аргумента, который имеет этот Макс, поэтому я могу распечатать поле сведений. Вызов args.aggregate(Max('rating')) просто возвращает самый высокий рейтинг. Я ищу аргумент с самым высоким рейтингом. - person Johnd; 11.05.2009
comment
Что не так с вашим выходным кодом - Argument.objects.order_by(-rating)[0]? - person AdamKG; 11.05.2009

В Django также есть функция 'latest(field_name = None), которая находит последние (макс. значение) запись. Он работает не только с полями даты, но также со строками и целыми числами.

Вы можете указать имя поля при вызове этой функции:

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

Или вы уже можете указать это имя поля в метаданных вашей модели:

from django.db import models

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

Теперь вы можете вызывать 'latest()' без каких-либо параметров:

max_rated_entry = YourModel.objects.latest()
return max_rated_entry.details
person Lutz Schönemann    schedule 14.06.2013
comment
Это отличный способ использования latest(). Если вам нужна запись с минимальным значением, вы можете использовать earliest(). - person SaeX; 21.05.2016
comment
latest() и earliest() также работают с полем без даты, но это побочный эффект реализации. Вы должны использовать <your-queryset>.order_by('<interested-field>').first() или <your-queryset>.order_by('<interested-field>').last(), чтобы убедиться, что ваш код по-прежнему будет работать, даже если разработчики Django изменят реализацию latest() и earliest() для работы только с полями даты. - person mrnfrancesco; 01.07.2017
comment
Это плохой ответ: 1) как уже было замечено ранее, это деталь реализации и может быть изменена в будущем 2) это не очень читабельно - максимальное число не обязательно является последним сохраненным (или в любом другом смысле) - person Mikhail Gerasimov; 19.06.2019

Я проверил это для своего проекта, он находит максимум/минимум за время O (n):

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)

Это гарантирует, что вы получите один из максимальных элементов эффективно, а не сортируете всю таблицу и получаете вершину (около O (n * logn)).

person afahim    schedule 21.06.2012
comment
Big-O иногда не оправдывает себя на практике, особенно для меньших n, где имеют значение коэффициенты и реализация. Ваш код находится в python/django, который скомпилирован в байт-код и может быть оптимизирован или не оптимизирован. База данных, вероятно, написана на языке, оптимизированном и скомпилированном для машинных инструкций. Кроме того, у базы данных нет реальной причины сортировать, если функция ищет только максимальное значение. Я хотел бы увидеть временные данные, прежде чем мне будет удобно использовать код ручной сборки вместо встроенной функции базы данных. - person benevolentprof; 18.08.2013
comment
@afahim Я не думаю, что код, который вы публикуете, полностью верен. если окажется, что у вас более одного максимума (скажем, у вас есть два приложения с 5 звездами), использование get вызовет ошибку. - person Raydel Miranda; 06.07.2018

Если вы также хотите получить значение, отличное от None, в случае, если таблица пуста (например, 0), объедините Max с Объединить:

from django.db.models import Max, Value
from django.db.models.functions import Coalesce

max_rating = SomeModel.objects.aggregate(
    max_rating=Coalesce(Max('rating'), Value(0))
)['max_rating']
person roskakori    schedule 20.04.2021

Возможно, чтобы улучшить ответ @afahim в отношении комментария @Raydel Miranda, если вам нужен случайный комментарий. Если вы хотите все, то используйте только фильтр

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.filter(rating=max_rating).first()
person Sona Pochybova    schedule 11.03.2021

сол 01:

from .models import MyMODEL

max_rating = MyMODEL.objects.order_by('-rating').first()

02 сол:

from django.db.models import Max
from .models import MyMODEL

max_rating = MyMODEL.objects.aggregate(Max('rating'))
person Dipta Dhar    schedule 31.07.2021