Существует большая статья от Slava Akhmechet названа Функциональное программирование Для Остальной части Нас (это было статьей, которая получила меня в FP btw). Среди преимуществ FP приносит, он неправославным образом подчеркивает следующее (которому я верю, способствует призыву к разработчикам программного обеспечения):
И затем продолжает обсуждать совершенство более традиционно обсужденных аспектов FP как функции высшего порядка, приправление карри, отложенные вычисления, оптимизация, абстрагируя управляющие структуры (хотя не обсуждая монады), бесконечные структуры данных, строгость, продолжения, сопоставление с образцом, закрытия и так далее.
Наиболее рекомендуемый!
Может быть, что-то вроде этого?
Food.objects.filter(consumer__user=user)\
.annotate(consumption_times=Count('consumer'))\
.order_by('consumption_times')
У меня очень похожая проблема. В принципе, я знаю, что вам нужен запрос SQL:
SELECT food.*, COUNT(IF(consumption.user_id=123,TRUE,NULL)) AS consumption_times
FROM food LEFT JOIN consumption ON (food.id=consumption.food_id)
ORDER BY consumption_times;
Я хочу, чтобы вы могли смешивать агрегатные функции и F-выражение, аннотировать F-выражения без агрегатной функции, иметь более богатый набор операций / функций для F-выражений и есть виртуальные поля, которые в основном являются автоматической аннотацией F-выражения. Чтобы вы могли сделать:
Food.objects.annotate(consumption_times=Count(If(F('consumer')==user,True,None)))\
.order_by('consumtion_times')
Кроме того, было бы неплохо просто иметь возможность более легко добавлять свои собственные сложные агрегатные функции, но пока вот хак, который добавляет для этого агрегатную функцию.
from django.db.models import aggregates,sql
class CountIf(sql.aggregates.Count):
sql_template = '%(function)s(IF(%(field)s=%(equals)s,TRUE,NULL))'
sql.aggregates.CountIf = CountIf
consumption_times = aggregates.Count('consumer',equals=user.id)
consumption_times.name = 'CountIf'
rows = Food.objects.annotate(consumption_times=consumption_times)\
.order_by('consumption_times')