Python Django ORM限制queryset只返回数据的子集
我在Django应用程序中有以下查询。用户字段是外键。结果可能包含1000个MyModel对象,但仅限于少数用户。我想将其限制为在查询的user\uu in=部分中每个用户返回5个MyModel对象。我最终应该拥有5*个或更少的MyModel对象Python Django ORM限制queryset只返回数据的子集,python,django,postgresql,django-orm,Python,Django,Postgresql,Django Orm,我在Django应用程序中有以下查询。用户字段是外键。结果可能包含1000个MyModel对象,但仅限于少数用户。我想将其限制为在查询的user\uu in=部分中每个用户返回5个MyModel对象。我最终应该拥有5*个或更少的MyModel对象 lfs = MyModel.objects.filter( user__in=[some,users,here,], active=True, follow=True, ) 通过ORM或使用Postgres的SQL都是可以接受
lfs = MyModel.objects.filter(
user__in=[some,users,here,],
active=True,
follow=True,
)
通过ORM或使用Postgres的SQL都是可以接受的
谢谢
编辑2
找到了一个更简单的方法来完成这个任务,我在下面添加了这个答案
编辑
评论中提到的一些链接提供了一些很好的信息,尽管没有一个真正适用于Postgres或Django ORM。对于将来寻找此信息的任何其他人,我对这些其他问题/asnwers中代码的修改如下
为了在Postgres9.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来限制它查找的用户,整个过程就会中断,它只返回每一行,而不是每个用户只返回5个。我想这就是你要查找的,我在其他帖子中没有看到它: 在其他示例中,它们在切片之前从queryset传递到list。例如,如果您制作了类似以下内容:
lfs = MyModel.objects.filter(
user__in=[some,users,here,],
active=True,
follow=True,
)[:10]
生成的SQL语句是一个在其子句中限制为10的查询
因此,您要查找的查询如下:
mymodel_ids = []
for user in users:
mymodel_5ids_for_user = (MyModel.objects.filter(
user=user,
active=True,
follow=True,
)[:5]).values_list('id', flat=True)
mymodel_ids.extend(mymodel_5ids_for_user)
lfs = MyModel.objects.filter(id__in=mymodel_ids)
在lfs中有MyModel的对象,您可以在其中查找每个用户的5个条目
我认为查询的数量至少是每个用户一个查询,以及一个使用该过滤器检索所有MyModel对象的查询
注意要过滤对象的顺序。如果您更改mymodel_5ids_for_用户查询的顺序,查询的前5个元素可能会更改。我想这就是您要查找的内容,我在其他帖子中没有看到: 在其他示例中,它们在切片之前从queryset传递到list。例如,如果您制作了类似以下内容:
lfs = MyModel.objects.filter(
user__in=[some,users,here,],
active=True,
follow=True,
)[:10]
生成的SQL语句是一个在其子句中限制为10的查询
因此,您要查找的查询如下:
mymodel_ids = []
for user in users:
mymodel_5ids_for_user = (MyModel.objects.filter(
user=user,
active=True,
follow=True,
)[:5]).values_list('id', flat=True)
mymodel_ids.extend(mymodel_5ids_for_user)
lfs = MyModel.objects.filter(id__in=mymodel_ids)
在lfs中有MyModel的对象,您可以在其中查找每个用户的5个条目
我认为查询的数量至少是每个用户一个查询,以及一个使用该过滤器检索所有MyModel对象的查询
注意要过滤对象的顺序。如果更改mymodel_5ids_for_user query的顺序,则查询的前5个元素可能会更改。这就是最终的结果,允许我仅选择少数用户,或通过删除行中的和mt.user_id来选择所有用户
SELECT * FROM mytable
WHERE (id, user_id, follow, active) IN (
SELECT id, likeable, user_id, follow, active FROM mytable mt
WHERE mt.user_id = mytable.user_id
AND mt.user_id IN (1, 2)
ORDER BY user_id LIMIT 5)
ORDER BY likeable
这就是最终起作用的地方,允许我通过删除行中的和mt.user_id,只选择少数用户,或选择所有用户
SELECT * FROM mytable
WHERE (id, user_id, follow, active) IN (
SELECT id, likeable, user_id, follow, active FROM mytable mt
WHERE mt.user_id = mytable.user_id
AND mt.user_id IN (1, 2)
ORDER BY user_id LIMIT 5)
ORDER BY likeable
它的可能副本是一个副本。我检查了一下,它似乎是另一个问题的答案,特别是第一段代码,回答了这个问题。顺便说一句,这被称为top-n查询。可能的重复是重复的。我检查了一下,似乎另一个问题的答案,特别是第一段代码,回答了这个问题。顺便说一句,这被称为top-n查询。-1,它总共会给出10个对象,任务是为每个用户获得5个或更少的对象。我知道我没有直接回答他的问题。这更像是一个评论,而不是一个完整的答案。但由于我的名声不好,我无法发表评论。我编辑我的答案是为了更具体地回答他的问题。。。对不起,我错了!下次我会更加小心…-1,它将给出10个对象,任务是为每个用户获得5个或更少的对象。我知道我没有直接回答他的问题。这更像是一个评论,而不是一个完整的答案。但由于我的名声不好,我无法发表评论。我编辑我的答案是为了更具体地回答他的问题。。。对不起,我错了!下次我会更小心的。。。