Выполнение этого в SQL возможно (и даже не так сложно).Однако получение количества дней в месяце зависит от СУБД, и нет общей функции базы данных Django, которая защитила бы вас от различных реализаций SQL.
Django позволяет легко обернуть ваши собственные функции в функции SQL.Например, для SQLite вы можете определить
class DaysInMonth(Func):
output_field = IntegerField()
def as_sqlite(self, compiler, connection):
return super().as_sql(
compiler,
connection,
function='strftime',
template='''
%(function)s("%%%%d",
%(expressions)s,
"start of month",
"+1 month",
"-1 day")
''',
)
Затем вы можете использовать DaysInMonth()
, чтобы разделить ваш счетчик на количество дней:
qs = (
SaleItem.objects
.annotate(date=Trunc('bill__date', aggregate))
.values('date')
.annotate(
sales = Count('bill', distinct=True),
sales_per_day = F('sales') / DaysInMonth('date')
)
)
Если округлено до целого числане достаточно, и вам нужен десятичный результат, это еще один обруч для прыжка:
sales_per_day=ExpressionWrapper(
Cast('sales', FloatField()) / DaysInMonth(F('date')),
DecimalField()
)
Если, боже упаси, вы хотите округлить в базе данных, а не в своем шаблоне, вам нужна другая пользовательская функция:
class Round(Func):
function = 'ROUND'
output_field = FloatField()
arity = 2
sales_per_day=Round(
Cast('sales', FloatField()) / DaysInMonth(F('date')),
2 # decimal precision
)
Таким образом, Django действительно гибок, но, как сказал Виллем, выполнение этого в Python избавит вас от некоторой боли, не теряя при этом существенной производительности (если она вообще есть).