我有一个看起来像这样的记录集(省略了无关的数据以保护容易厌倦):
id | user_id | created | units
----+---------+-------------------------------+-------
1 | 1 | 2011-04-18 15:43:02.737063+00 | 20
2 | 1 | 2011-04-18 15:43:02.737063+00 | 4
3 | 1 | 2011-04-18 15:46:48.592999+00 | -1
4 | 1 | 2011-04-19 12:02:10.687587+00 | -1
5 | 1 | 2011-04-19 12:09:20.039543+00 | -1
6 | 1 | 2011-04-19 12:11:21.948494+00 | -1
7 | 1 | 2011-04-19 12:15:51.544394+00 | -1
8 | 1 | 2011-04-19 12:16:44.623655+00 | -1
我希望得到一个看起来像这样的结果:
id | user_id | created | units
----+---------+-------------------------------+-------
8 | 1 | 2011-04-19 12:16:44.623655+00 | 14
2 | 1 | 2011-04-18 15:43:02.737063+00 | 4
所以我自然而然地期待.annotate()
:
u = User.objects.get(pk=1)
(MyModel.objects.filter(user=u)
.values("id","user","created")
.annotate(stuff=Sum("units"))
)
问题在于我需要对象,而不是单个词典列表。我需要附加到这些对象的方法可用。有关如何做到这一点的任何想法?
修改: 我应该指出我尝试使用.values()因为没有它我会得到一堆带注释的对象,但是会有8个(如上面的第一个查询中),而不是2(如第二个)结果如上)。我的猜测是它没有组合行,因为在那里有一个时间戳使行不同:
MyModel.objects.filter(user=u).annotate(Sum("units"))
# Returns 8 records, not 2 as expected
答案 0 :(得分:5)
当我最初提出这个问题时,看起来有些混乱,因此当我实际上不是问题时,我被指示不使用.values()
。问题是Django的.annotate()
不允许用计算值覆盖列属性,只允许用附加数据注释对象。这实际上是有道理的,因为如果你想要一个返回的对象,你希望能够假设有问题的对象实际上代表了数据库中的一行,而不是计算值覆盖列值的混合。
但是,这对我不起作用,因为上述功能意味着对于created
(时间戳)等列,您无法使用.values()
获取我想要的计算值。那并没有给我任何对象。
所以,我选择了下一个最好的东西:.raw()
:
query = """
SELECT
ep.product_id AS product_id,
ep.user_id AS user_id,
MAX(ep.created) AS created,
SUM(eup.units) AS units
FROM
ecom_unitpermission AS eup
WHERE
ep.user_id = 1
GROUP BY
ep.product_id,
ep.user_id
"""
for perm in MyModel.objects.raw(query):
print "%15s %3s %s" % (perm.product.name, perm.units, perm.product.somemethod())
使用.defer()
可能会为我做到这一点,不过there appears to be a bug in Django 1.3 when combining that with .annotate()
答案 1 :(得分:3)
问题不是注释,而是对值的调用。 documentation非常清楚地表明annotate适用于查询集。值调用返回值的字典并使您无法访问模型。
编辑添加:如果您只想恢复某些字段但仍有模型,请使用defer代替值
答案 2 :(得分:0)
Annotate返回一个查询集,但你也调用了.values(),它总是返回一个字典。