Джанго: Сгруппировать?

Я ищу что-то вроде следующего:

previous_invoices = Invoice.objects.filter(is_open=False)
                                   .order_by('-created')
                                   .group_by('user')

но group_by() не существует...

Это позволит найти самый последний закрытый счет для каждого пользователя.

Этот API агрегации, по-видимому, позволяет вам делать подобные вещи для подсчета и суммы, но мне не нужен счет или сумма или что-то еще, мне действительно нужны объекты счета!


person mpen    schedule 13.03.2010    source источник
comment
определена ли вещь selected при использовании group by? Я ожидаю, что это даст разные результаты в зависимости от реализации sql...   -  person user3012759    schedule 07.08.2017
comment
@user3012759 user3012759 Нет. Упорядочивание происходит после группировки, и какая запись, которую вы возвращаете в эту группу, не определена. Мне потребовалось некоторое время, чтобы действительно понять это. ONLY_FULL_GROUP_BY должен быть включен по умолчанию IMO, поэтому что вы не делаете эту ошибку.   -  person mpen    schedule 08.08.2017
comment
Привет, @mpen, я добавил более свежую попытку ответить. Хочешь взглянуть?   -  person John Moutafis    schedule 11.08.2017
comment
@JohnMoutafis Конечно, я могу посмотреть. Я больше не работаю с Django, но, похоже, было бы полезно, если бы я это сделал :-)   -  person mpen    schedule 11.08.2017
comment
Полезно знать @mpen :)   -  person John Moutafis    schedule 12.08.2017


Ответы (2)


Вариант 1:

Хотя group_by() не существует в Django, вы можете попытаться получить последний закрытый счет для каждого пользователя, используя latest() и фильтр для пользователя:

previous_invoices = Invoice.objects.filter(user=my_user, is_open=False)
                                   .latest('created') 

Для более старых версий Django, где latest() не существует, запрос будет выглядеть так:

previous_invoices = Invoice.objects.filter(user=my_user, is_open=False)
                                   .order_by('-created')[0]

Вариант 2:

ОБНОВЛЕНИЕ: с тех пор я добавил здесь пример стиля вопросов и ответов: Как выполнить GROUP BY... COUNT или SUM в Django ORM?, который показывает, как имитировать операцию GROUP BY в Django ORM.

Если вы абсолютно хотите создать эффекты group_by, вы можете создать его вручную, как показано в принятом ответе здесь: Django GROUP BY значение поля.

  1. Используйте .values_list() с flat=True, чтобы получить список существующие значения в вашей базе данных (если вы не знаете их заранее). Также используйте .distinct() для устранения повторяющихся значений, так как они нам не нужны:

    value_list = MyModel.objects.values_list(
        'interesting_field', flat=True
    ).distinct()
    
  2. Теперь повторите value_list и заполните свой словарь:

    group_by_value = {}
    for value in value_list:
        group_by_value[value] = MyModel.objects.filter(interesting_field=value)
    

Теперь словарь group_by_value содержит в качестве ключей отдельные значения в вашем interesting_field, а в качестве значений — объекты набора запросов, каждый из которых содержит записи MyModel с interesting_field=a value from value_list.


Примечание.

Существует эта библиотека django-group-by, которая утверждает, что добавляет group_by() к Django, вы можете проверить.

person John Moutafis    schedule 07.08.2017

Вот эта страница 2007 года. который взломал его на django, но это было бы спорным, поскольку в версии до 1.1 все равно есть недокументированный group_by`. Но эта ветка годичной давности, кажется, содержит некоторые идеи. . По сути:

Django намеренно не раскрывает «GROUP BY» или что-то подобное в ORM. Хотя тот факт, что мы работаем с серверной частью реляционного хранилища, иногда просачивается наружу, API ORM довольно независим от SQL. Вместо этого мы раскрываем отдельные части функциональности, которые реализуются с использованием "GROUP BY" при преобразовании в SQL (и вполне могут быть реализованы каким-то совершенно другим набором волшебных фей с другой серверной частью системы хранения).

См. также упоминания об использовании extra, а также о волшебных способах, которыми это может потерпеть неудачу. Удачи.

person Adriano Varoli Piazza    schedule 13.03.2010