在 Django 中按日期分组
Group by date in Django
我正在尝试实现以下 SQL 查询的结果
SELECT
UNIX_TIMESTAMP(DATE((FROM_UNIXTIME(`timestamp`)))) AS `x`,
COUNT(`timestamp`) as y
FROM somedb.events
WHERE user_id=3 AND
`timestamp` > 1612117800 AND
`timestamp` < 1614450600 AND
`kind`='food'
GROUP BY `x`
ORDER BY `x` desc;
使用 Django ORM。预期输出:
[
{
"x": 1613759400,
"y": 2
},
{
"x": 1612463400,
"y": 1
}
]
这是我到目前为止尝试过的:
queryset = events.objects.filter(
user=request.user,
timestamp__range=dates
)
第一种方法:
result = queryset.annotate(
trunc_date_timestamp=Func(
Value(
TruncDate(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
)
)
),
function='UNIX_TIMESTAMP',
output_field=models.IntegerField()
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
这会产生输出:
[
{
"x": 0,
"y": 3
}
]
第二种方法:
result = queryset.annotate(
trunc_date_timestamp=Func(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
),
function='UNIX_TIMESTAMP'
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
产生输出:
[
{
"x": 1613831760,
"y": 1
},
{
"x": 1613810160,
"y": 1
},
{
"x": 1612520520,
"y": 1
}
]
我终于成功了。我在这两种方法中都犯了小错误。
第一种方法:
result = ueryset.annotate(
trunc_date_timestamp=Func(
TruncDate(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField() # <<--- This is must
)
),
function='UNIX_TIMESTAMP',
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
删除了 Value()
API 并将 output_field=models.DateTimeField()
添加到内部 Func()
API。 output_field
将确保由内部 Func()
API 编辑的字段 return 必须是 models.DateField()
类型,TruncDate
将应用于该字段。
第二种方法:
queryset = queryset.annotate(
trunc_date_timestamp=Func(
Cast(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
),
output_field=models.DateField()
),
function='UNIX_TIMESTAMP'
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
本来以为
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
)
这将 return 一个 models.DateField()
类型的字段,但是 我不知道为什么它不工作而且失败了!!! 所以我改用 Cast()
方法并将 returned 表达式转换为 models.DateField()
以使其工作。
虽然这个解决方案有效,但我强烈认为第二种方法的原始代码也应该有效,因为如果我正确理解 Func()
表达式,那么
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
)
和
Cast(
Func(
F('timestamp'),
function='FROM_UNIXTIME'
),
output_field=models.DateField()
)
应该会产生相同的结果。
我正在尝试实现以下 SQL 查询的结果
SELECT
UNIX_TIMESTAMP(DATE((FROM_UNIXTIME(`timestamp`)))) AS `x`,
COUNT(`timestamp`) as y
FROM somedb.events
WHERE user_id=3 AND
`timestamp` > 1612117800 AND
`timestamp` < 1614450600 AND
`kind`='food'
GROUP BY `x`
ORDER BY `x` desc;
使用 Django ORM。预期输出:
[
{
"x": 1613759400,
"y": 2
},
{
"x": 1612463400,
"y": 1
}
]
这是我到目前为止尝试过的:
queryset = events.objects.filter(
user=request.user,
timestamp__range=dates
)
第一种方法:
result = queryset.annotate(
trunc_date_timestamp=Func(
Value(
TruncDate(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
)
)
),
function='UNIX_TIMESTAMP',
output_field=models.IntegerField()
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
这会产生输出:
[
{
"x": 0,
"y": 3
}
]
第二种方法:
result = queryset.annotate(
trunc_date_timestamp=Func(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
),
function='UNIX_TIMESTAMP'
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
产生输出:
[
{
"x": 1613831760,
"y": 1
},
{
"x": 1613810160,
"y": 1
},
{
"x": 1612520520,
"y": 1
}
]
我终于成功了。我在这两种方法中都犯了小错误。
第一种方法:
result = ueryset.annotate(
trunc_date_timestamp=Func(
TruncDate(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField() # <<--- This is must
)
),
function='UNIX_TIMESTAMP',
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
删除了 Value()
API 并将 output_field=models.DateTimeField()
添加到内部 Func()
API。 output_field
将确保由内部 Func()
API 编辑的字段 return 必须是 models.DateField()
类型,TruncDate
将应用于该字段。
第二种方法:
queryset = queryset.annotate(
trunc_date_timestamp=Func(
Cast(
Func(
F('timestamp'),
function='FROM_UNIXTIME',
),
output_field=models.DateField()
),
function='UNIX_TIMESTAMP'
)
).values(x=F('trunc_date_timestamp')).annotate(y=models.Count('x')).order_by('-x')
本来以为
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
)
这将 return 一个 models.DateField()
类型的字段,但是 我不知道为什么它不工作而且失败了!!! 所以我改用 Cast()
方法并将 returned 表达式转换为 models.DateField()
以使其工作。
虽然这个解决方案有效,但我强烈认为第二种方法的原始代码也应该有效,因为如果我正确理解 Func()
表达式,那么
Func(
F('timestamp'),
function='FROM_UNIXTIME',
output_field=models.DateField()
)
和
Cast(
Func(
F('timestamp'),
function='FROM_UNIXTIME'
),
output_field=models.DateField()
)
应该会产生相同的结果。