问题
我想在 Django 中使用COUNT(DISTINCT field)
with aGROUP BY
子句。据我了解,COUNT(DISTINCT...
只能通过使用extra
查询集来实现。
我的简化模型是:
class Site(models.Model):
name = models.CharField(max_length=128, unique=True)
class Application(models.Model):
name = models.CharField(max_length=64)
version = models.CharField(max_length=13, db_index=True)
class User(models.Model):
name = models.CharField(max_length=64)
site = models.ForeignKey(Site, db_index=True)
class Device(models.Model):
imei = models.CharField(max_length=16, unique=True)
applications = models.ManyToManyField(Application, null=True, db_index=True, through='ApplicationUsage')
user = models.ForeignKey(User, null=True, db_index=True)
class ApplicationUsage(models.Model):
activity = models.DateField(db_index=True)
application = models.ForeignKey(Application)
device = models.ForeignKey(Device)
我的目标是在给定一段时间内的应用程序活动的情况下,为每个站点创建一个包含不同设备计数的站点对象列表,例如
stats_site.name deviceCount
ALBI 32
AMPLEPUIS 42
...
我试试这段代码:
qs = models.Site.objects.filter(user__device__applicationusage__activity__range=[startDay, endDay])\
.extra(select={'deviceCount' : 'COUNT(DISTINCT `stats_device`.`id`)'})\
.values('name', 'deviceCount')\
生成的 SQL 是:
SELECT (COUNT(DISTINCT stats_device.id)) AS deviceCount, stats_site.name
FROM stats_site
INNER JOIN stats_user ON (stats_site.id = stats_user.site_id)
INNER JOIN stats_device ON (stats_user.id = stats_device.user_id)
INNER JOIN stats_applicationusage ON (stats_device.id = stats_applicationusage.device_id)
WHERE stats_applicationusage.activity BETWEEN '2013-07-01' AND '2013-07-03'
结果显然是错误的,因为它缺少GROUP BY
子句,应该是GROUP BY stats_site.name
问题是:我不知道如何GROUP BY
使用annotate
函数或其他添加正确的。
解决方案
distinct=True
在Count
函数上使用annotate
:
qs = models.Site.objects.filter(habileouser__device__applicationusage__activity__range=[startDay, endDay])\
.annotate(deviceCount=Count('habileouser__device', distinct=True))\
.values('name', 'deviceCount')