2012-03-01 40 views
1

我在Django應用程序中有以下查詢。用戶字段是一個外鍵。結果可能包含1000個MyModel對象,但僅適用於少數用戶。我想限制它在查詢的user__in=部分中爲每個用戶返回的5個MyModel對象。我應該以5 *#用戶或更少的MyModel對象結束。Django ORM限制queryset只返回數據的一個子集

lfs = MyModel.objects.filter(
    user__in=[some,users,here,], 
    active=True, 
    follow=True, 
) 

通過ORM或SQL(使用Postgres)都是可以接受的。

感謝

EDIT 2

發現了一個簡單的方法來完成這件事,我已經添加了如下回答。

編輯

一些在評論中提到的鏈接有一些很好的信息,但沒有人真的在Postgres或者Django的ORM工作。對於其他人在未來尋找這些信息,我在這些其他問題/ asnwers的代碼的適應。

爲了實現這一點是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個。

+2

的可能重複[Django的:如何選擇行有限數量的每一個外鍵(http://stackoverflow.com/questions/6705579/django-how-to-select-a-limited - 行數爲每個外鍵) – DrTyrsa 2012-03-01 08:00:18

+0

它**是**重複。我查了一下,似乎是另一個問題的答案,尤其是代碼的第一部分,回答了這個問題。 – jpic 2012-03-01 09:38:31

+1

順便說一句,這被稱爲前n個查詢。 – jpic 2012-03-01 10:42:13

回答

2

這是什麼結束了工作,並允許我只選擇少數用戶,或所有用戶(通過刪除AND mt.user_id IN()行)。

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 
-1

我想這是您要尋找的(我沒有看到它在其他職位):

https://docs.djangoproject.com/en/dev/topics/db/queries/#limiting-querysets

在其他例子,他們從查詢集「切片」之前列出通過。如果你做出這樣的事情(例如):

lfs = MyModel.objects.filter(
     user__in=[some,users,here,], 
     active=True, 
     follow=True, 
    )[:10] 

產生的SQL它是一個帶有LIMIT 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」查詢的順序,則查詢的前5個元素可能會更改。

+0

-1,它將總共給出10個對象,並且任務是爲每個用戶獲得5個或更少的對象。 – DrTyrsa 2012-03-01 13:30:07

+0

我知道我沒有直接回答他的問題。它更像是一個評論,而不是一個完整的答案。但是由於我的低信譽,我無法添加評論。我編輯我的答案,以便更具體地瞭解他的問題......對不起,我的錯誤!下一次我會更加小心...... – marianobianchi 2012-03-02 01:09:05

相關問題