我有以下django模型(映射到表'A'):
class A(models.Model):
name = models.CharField(max_length=64, null=False)
value = models.IntegerField()
...
我想在顶部执行以下简单查询:
select avg(case
when (value > 0 and value <= 50) then 0
when (value > 50 and value < 70) then 50
else 100 end)
from A
where ...
我正在尝试避免原始SQL - 如何使用django实现(在上面的示例中我使用avg,但同样的问题也与max,min,sum等相关)?
我尝试使用extra和aggregate:
extra(select={'avg_field': case_when_query})
和
aggregate(Avg('avg_field')),
但聚合函数仅适用于模型字段,因此此处不能使用额外字段。 如何用django完成?
感谢您的帮助
答案 0 :(得分:4)
可以做什么仍然允许我们使用django queryset是这样的:
qs = A.objects.extra(select={"avg_field":
"avg(case when...)"}).filter(...).values("avg_field")
使用结果:
qs[0]["avg_field"]
这将允许所需的功能。
答案 1 :(得分:3)
据我所知,(不幸的是)没有办法在不诉诸原始SQL的情况下完成您所描述的内容。
那就说 是一种计算平均值的方法,如果你愿意稍微对数据进行非规范化的话。例如,您可以添加一个名为average_field
的新列,该列会自动设置为save()
上的相应值。您可以覆盖save()
或点按信号以自动执行此操作。例如,
class A(models.Model):
name = models.CharField(max_length=64, null=False)
value = models.IntegerField()
average_field = models.IntegerField(default = 0)
def _get_average_field(self):
# Trying to match the case statement's syntax.
# You can also do 0 < self.value <= 50
if self.value > 0 and self.value <= 50:
return 0
elif self.value > 50 and self.value < 70:
return 50
else:
return 100
def save(self, *args, **kwargs):
if self.value:
self.average_field = self._get_average_field()
super(A, self).save(*args, **kwargs)
一旦你这样做,你的查询变得非常容易。
A.objects.filter(...).aggregate(avg = Avg('average_field'))
答案 2 :(得分:3)
Django 1.8将支持开箱即用的CASE WHEN表达式,请参阅https://docs.djangoproject.com/en/dev/ref/models/conditional-expressions/