Python Django ORM限制queryset只返回数据的子集

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都是可以接受

我在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都是可以接受的

谢谢

编辑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个或更少的对象。我知道我没有直接回答他的问题。这更像是一个评论,而不是一个完整的答案。但由于我的名声不好,我无法发表评论。我编辑我的答案是为了更具体地回答他的问题。。。对不起,我错了!下次我会更小心的。。。