【发布时间】:2012-03-01 07:54:46
【问题描述】:
我在 Django 应用程序中有以下查询。用户字段是外键。结果可能包含 1000 个 MyModel 对象,但仅限于少数用户。我想将其限制为在查询的 user__in= 部分中为每个用户返回 5 个 MyModel 对象。我应该得到 5*#users 或更少的 MyModel 对象。
lfs = MyModel.objects.filter(
user__in=[some,users,here,],
active=True,
follow=True,
)
通过 ORM 或 SQL(使用 Postgres)都是可以接受的。
谢谢
编辑 2
找到了一种更简单的方法来完成这项工作,我已将其添加为下面的答案。
编辑
cmets 中提到的一些链接有一些很好的信息,尽管没有一个真正适用于 Postgres 或 Django ORM。对于将来寻找此信息的其他人,我在其他问题/回答中对代码的改编在这里。
要实现这是 postgres 9.1,我必须使用 pgperl 创建几个函数(这也需要我安装 pgperl)
CREATE OR REPLACE FUNCTION set_int_var(name text, val bigint) RETURNS bigint AS $$
if ($_SHARED{$_[0]} = $_[1]) {
return $_[1];
} else {
return $_[1];
}
$$ LANGUAGE plperl;
CREATE OR REPLACE FUNCTION get_int_var(name text) RETURNS bigint AS $$
return $_SHARED{$_[0]};
$$ LANGUAGE plperl;
我的最终查询如下所示
SELECT x.id, x.ranking, x.active, x.follow, x.user_id
FROM (
SELECT tbl.id, tbl.active, tbl.follow, tbl.user_id,
CASE WHEN get_int_var('user_id') != tbl.user_id
THEN
set_int_var('rownum', 1)
ELSE
set_int_var('rownum', get_int_var('rownum') + 1)
END AS
ranking,
set_int_var('user_id', tbl.user_id)
FROM my_table AS tbl
WHERE tbl.active = TRUE AND tbl.follow=TRUE
ORDER BY tbl.user_id
) AS x
WHERE x.ranking <= 5
ORDER BY x.user_id
LIMIT 50
唯一的缺点是,如果我尝试使用 user_id IN () 来限制它寻找的用户,整个事情就会中断,它只会返回每一行,而不是每个用户只返回 5 个。
【问题讨论】:
-
它是重复的。我查了一下,似乎另一个问题的答案,尤其是第一个 sn-p 代码,回答了这个问题。
-
顺便说一句,这被称为 top-n 查询。
标签: python django postgresql django-orm