class Category(models.Model):
pass
class Item(models.Model):
cat = models.ForeignKey(Category)
我想为每个类别选择一个项目,这是执行此操作的查询语法吗?
答案 0 :(得分:2)
您的问题并不完全清楚:既然您没有另外说明,我将假设您不关心为每个类别选择哪个项目,只需要您需要任何人。如果情况并非如此,请更新问题以澄清。
tl;博士版:没有记录 明确使用
GROUP BY
的方法 Django中的语句,除了使用 原始查询。请参阅底部以获取相同的代码。
问题在于,在SQL中寻找你正在寻找的东西需要一点点黑客攻击。您可以通过在命令行输入sqlite3 :memory:
轻松尝试此示例:
CREATE TABLE category
(
id INT
);
CREATE TABLE item
(
id INT,
category_id INT
);
INSERT INTO category VALUES (1);
INSERT INTO category VALUES (2);
INSERT INTO category VALUES (3);
INSERT INTO item VALUES (1,1);
INSERT INTO item VALUES (2,2);
INSERT INTO item VALUES (3,3);
INSERT INTO item VALUES (4,1);
INSERT INTO item VALUES (5,2);
SELECT id, category_id, COUNT(category_id) FROM item GROUP BY category_id;
返回
4|1|2
5|2|2
3|3|1
您正在寻找的是(每个类别ID的一个项目ID),尽管有无关的COUNT。要应用GROUP BY,需要计数(或其他一些聚合函数)。
注意:这将忽略不包含任何项目的类别,这似乎是明智的行为。
现在问题变成了,如何在Django中做到这一点?
显而易见的答案是使用Django's aggregation/annotation support,特别是将annotate与values结合使用,recommend elsewhere与Django中的GROUP查询相结合。
阅读这些帖子,似乎我们可以用
完成我们正在寻找的东西Item.objects.values( 'ID')。注释(unneeded_count =计数( 'CATEGORY_ID'))
然而,这不起作用。 Django在这里做的不仅仅是GROUP BY "category_id"
,而是选择所有字段的组(即GROUP BY "id", "category_id"
)1。我不相信有一种方法(至少在公共API中)改变这种行为。
解决方案是回退到原始SQL:
qs = Item.objects.raw('SELECT *, COUNT(category_id) FROM myapp_item GROUP BY category_id')
1:请注意,您可以检查Django正在运行的查询:
from django.db import connection
print connection.queries[-1]
还有许多其他可能的方法,但大多数都有(可能是严重的)性能问题。这是一对夫妇:
items = []
for c in Category.objects.all():
items.append(c.item_set[0])
这是一种更加清晰和灵活的方法,但明显的缺点是需要更多的数据库命中。
items = Item.objects.select_related()
然后自己进行分组/过滤(在Python中)。
同样,这可能比使用原始SQL更清晰,只需要一个查询,但这一个查询可能非常大(它将返回所有项目及其类别)并且自己进行分组/过滤可能效率低于让数据库为你做。