我有一个销售模型,当按month
,week
,year
分组时,我想计算(交易数)/(天数)。
class SaleItem(models.Model):
id = models.UUIDField(default=uuid4, primary_key=True)
bill = models.ForeignKey()
item = models.ForeignKey('item')
quantity = models.PositiveSmallIntegerField()
price = models.DecimalField(max_digits=13, decimal_places=3, default=0)
因此,如果按月对销售进行分组,则每个月将变成(该月的交易次数/天数)。现在,如果按年份将销售额分组,则变为(该年的交易次数/天数)
当前我可以获得交易数量
aggregate = 'month' # parameter
# get number of transactions
SaleItem.objects.annotate(date=Trunc('bill__date', aggregate)).values('date').annotate(sales=Count('bill', distinct=True))
但是我如何将每个计数除以该组中的天数呢?
答案 0 :(得分:1)
可以在SQL中执行(甚至没有那么困难)。但是,获取一个月中的天数是RDBMS特定的,并且没有通用的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确实非常灵活,但是正如Willem所说,用Python进行操作会为您省去一些麻烦,而又不会损失任何性能(如果有的话)。