如何编写Django QuerySet正确计算DateTimeField的平均值和分组?

时间:2015-02-27 06:15:53

标签: python django django-models django-queryset

这是我的Django模型:

class MyModel(models.Model):
    a = IntegerField()
    b = DateTimeField()

以下是我在此模型上执行的QuerySet,用于查找b的每个值的计数,最小值,最大值和平均值a

>>> from django.db.models import Count, Max, Min, Avg
>>> MyModel.objects.extra(
...    select={'avg': 'AVG(UNIX_TIMESTAMP(b))'}
... ).values('a').annotate(
...     count=Count('b'), 
...     min=Min('b'), 
...     max=Max('b'),
... )

以下是QuerySet的结果:

[
  {'a': 1, 'count': 5, 'min': datetime.datetime(2015, 2, 26, 1, 8, 21, tzinfo=<UTC>), 'max': datetime.datetime(2015, 2, 26, 1, 8, 22, tzinfo=<UTC>)}, 
  {'a': 2, 'count': 2, 'min': datetime.datetime(2015, 2, 26, 1, 8, 21, tzinfo=<UTC>), 'max': datetime.datetime(2015, 2, 26, 1, 8, 22, tzinfo=<UTC>)}
]

如您所见,QuerySet的结果不包括我计算的平均字段。我怎么能在那里得到它?我尝试了很多不同的排列。但是,如果我可以获得avg字段,那么它似乎会使a的分组变得混乱。

1 个答案:

答案 0 :(得分:0)

您可以使用raw sql query

,而不是使用Django ORM
from django.db import connection
query = """
SELECT `a`,
       COUNT(b) AS `count`,
       MAX(b) AS `max`,
       AVG(UNIX_TIMESTAMP(b)) AS `avg`,
       MIN(b) AS `min`
FROM `<appname>_<modelname>`
GROUP BY `a`
"""
cursor = connection.cursor()
cursor.execute(query)
result = cursor.fetchall()

这会为您提供之类的

(
    (a value1, count, max, avg as unix timestamp, min), ...
    (a value2, count, max, avg as unix timestamp, min), ...
    (a value3, count, max, avg as unix timestamp, min), ...
)

否则,使用Django的ORM最接近的事情就是放弃额外子句中的UNIX_TIMESTAMP转换:

from django.db.models import Count, Min, Max, Avg
MyModel.objects.all().values('a').annotate(
    count=Count('b'), 
    max=Max('b'), 
    avg=Avg('b'), 
    min=Min('b')
)

不幸的是,这会给你average as a float

[
    {
        'count': 15366, 
         'a': 0, 
         'avg': 19898862327498.82, 
         'min': datetime.datetime(1900, 1, 1, 0, 0), 
         'max': datetime.datetime(2012, 7, 3, 0, 0)
    }, {
         'count': 1726, 
         'a': 1, 
         'avg': 19785827400927.0, 
         'min': datetime.datetime(1920, 8, 25, 0, 0), 
         'max': datetime.datetime(1994, 12, 29, 0, 0)
    }, 
    ...

您可以尝试使用

之类的内容
import datetime
datetime.datetime.strptime(str(int(ts)), '%Y%m%d%H%M%S%f')

将它转换回datetime对象,虽然这将是一个近似值,所以我建议使用原始sql。