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

2024-04-26 12:46:01 发布

您现在位置:Python中文网/ 问答频道 /正文

class Category(models.Model):
    pass

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

我想为每个类别选择一个项目,这是dothis的查询语法?在


Tags: 项目modelmodels语法passitem类别class
1条回答
网友
1楼 · 发布于 2024-04-26 12:46:01

你的问题并不完全清楚:既然你没有说别的,我就假设你不在乎为每个类别选择哪一项,只是你需要任何一项。如果不是这样,请更新问题以澄清。在

tl;dr version: there is no documented way to explicitly use GROUP BY statements in Django, except by using a raw query. See the bottom for code to do so.

问题是,在执行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;

退货

^{pr2}$

这就是您要查找的(每个类别id对应一个item id),尽管有一个无关的计数。需要count(或其他一些聚合函数)才能应用groupby。在

注意:这将忽略不包含任何项目的类别,这似乎是明智的行为。在

现在的问题是,如何在Django中做到这一点?在

显而易见的答案是使用Django's aggregation/annotation support,特别是将annotate和{a3}结合使用recommendelsewhere来对Django中的查询进行分组。在

看了这些帖子,我们似乎可以完成我们想要的

在项.对象.值('id').annotate(不需要的_count=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更清楚,只需要一个查询,但这一个查询可能非常大(它将返回所有项及其类别),并且自己进行分组/筛选的效率可能不如让数据库为您完成。在

相关问题 更多 >