Django 的 .annotate() 可以返回对象吗?
我有一个看起来像这样的记录集(省略了无关的数据以保护容易无聊的人):
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
I have a record set that looks like this (extraneous data omitted to protect the easily bored):
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
And I'd like to get a result that looks like this:
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
So I naturally look to .annotate()
:
u = User.objects.get(pk=1)
(MyModel.objects.filter(user=u)
.values("id","user","created")
.annotate(stuff=Sum("units"))
)
The problem is that I want objects, not a single list of dictionaries. I need the methods attached to those objects to be available. Any ideas as to how to do this?
Edit:
I should have pointed out that I tried using .values() because without it I would get a bunch of annotated objects alright, but there would be 8 of them (as in the first query above), and not 2 (as in the second result above). My guess is that it's not combining the rows because there's a timestamp in there making the rows different:
MyModel.objects.filter(user=u).annotate(Sum("units"))
# Returns 8 records, not 2 as expected
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
当我最初提出这个问题时,看起来似乎有些混乱,因此当这实际上不是问题时,我被指示不要使用
.values()
。问题是 Django 的.annotate()
不允许用计算值覆盖列属性,而只用附加数据注释对象。这确实是有道理的,因为如果您想要返回一个对象,您希望能够假设该对象实际上代表数据库中的一行,而不是覆盖列值的计算值的混杂。但是,这对我来说不起作用,因为上述功能意味着对于像
created
(时间戳)这样的列,如果不使用.values() 就无法获得我想要的计算值
...这并没有给我对象。所以,我选择了下一个最好的事情:
.raw()
:使用
.defer()
可能已经为我做到了这一点,尽管 与.annotate() 结合使用时,Django 1.3 中似乎存在错误
It looks like there was some confusion when I initially asked the question, and as a result I was directed to not use
.values()
when that wasn't actually the problem. The problem is that Django's.annotate()
doesn't allow for the overwriting of column properties with calculated values, and only annotates objects with additional data. This makes sense really, since if you want an object returned, you want to be able to assume that the object in question actually represents a row in the database, and not a mishmash of calculated values overwriting column values.However, this didn't work for me, because the above functionality means that with columns like
created
(a timestamp) you can't get the calculated values I wanted without using.values()
... and that doesn't give me objects.So, I opted for the next best thing:
.raw()
:Using
.defer()
might have done this for me, though there appears to be a bug in Django 1.3 when combining that with.annotate()
问题不在于注释,而在于对值的调用。 文档非常清楚地表明注释适用于查询集。值调用会返回值字典,并使您无法访问模型。
编辑添加:如果您只想恢复某些字段但仍然有模型,则使用 defer 而不是值
The problem isn't annotate but the call to values. The documentation quite clearly show that annotate works on querysets. It is the values call that returns the dictionary of values and loses you the ability to access the models.
Edit to add: If you only want to bring back certain fields but still have models then use defer instead of values
Annotate 返回一个查询集,但您还调用 .values() ,它将始终返回一个字典。
Annotate returns a queryset, but you're also calling .values() which will always return a dictionary.