查询语法,为每个类别选择一个项目

时间:2010-12-24 05:37:23

标签: python django

class Category(models.Model):
    pass

class Item(models.Model):
    cat = models.ForeignKey(Category)

我想为每个类别选择一个项目,这是执行此操作的查询语法吗?

1 个答案:

答案 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,特别是将annotatevalues结合使用,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]

编辑:

还有许多其他可能的方法,但大多数都有(可能是严重的)性能问题。这是一对夫妇:

1。从每个类别中选择一个项目。

items = []
for c in Category.objects.all():
    items.append(c.item_set[0])

这是一种更加清晰和灵活的方法,但明显的缺点是需要更多的数据库命中。

2。使用select_related

items = Item.objects.select_related()

然后自己进行分组/过滤(在Python中)。

同样,这可能比使用原始SQL更清晰,只需要一个查询,但这一个查询可能非常大(它将返回所有项目及其类别)并且自己进行分组/过滤可能效率低于让数据库为你做。