2012-03-01 8 views
1

Djangoアプリケーションで次のクエリを使用しています。ユーザーフィールドは外部キーです。結果には、1000個のMyModelオブジェクトが含まれていますが、ユーザーのほんの一部です。クエリのuser__in=部分にユーザーごとに返される5つのMyModelオブジェクトに制限したいと思います。私は5 *#ユーザー以下のMyModelオブジェクトで終わるはずです。Django ORMクエリーセットを制限してデータのサブセットのみを返す

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

ORMまたはSQL(Postgresを使用)のいずれかを使用できます。

おかげ

EDIT 2

は、私は以下の答えとして追加した、これは終らする簡単な方法を見つけました。どれも本当にPostgresのか、DjangoのORMで働いていないものの

EDIT

は、コメントに記載されたリンクのいくつかは、いくつかの良い情報を持っていました。将来この情報を探している他の人のために、他の質問/執筆者のコードの私の適応がここにあります。

これは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

の可能重複[ジャンゴ:?それぞれの外部キーの行の限られた量を選択する方法](http://stackoverflow.com/questions/6705579/django-how-to-select-a-limited - 各外部キーの行数) – DrTyrsa

+0

** **は重複しています。チェックしたところ、他の質問の回答、特にコードの最初の断片がこの質問に答えているようです。 – jpic

+1

ところで、これはトップnクエリと呼ばれます。 – jpic

答えて

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というクエリーが作成されます。 (ユーザーあたり5エントリー)を探しているところLFS mymodelというあなたのオブジェクトで

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) 

持つ:

だから、あなたが探しているクエリは、このようなものになるだろう。

私は、クエリの数は、少なくとも、ユーザーごとに、そのフィルタをすべてmymodelというオブジェクトを取得するための1だと思います。

オブジェクトをフィルタリングする順序に注意してください。 "mymodel_5ids_for_user"クエリの順序を変更すると、クエリの最初の5つの要素が変更される可能性があります。

+0

-1とすると、合計10個のオブジェクトが与えられ、タスクごとに5個以下のオブジェクトを取得します。 – DrTyrsa

+0

私は彼の質問に直接答えなかったことを知っています。それは完全な答えよりもコメントのようなものでした。しかし私は評判が低いのでコメントを追加できませんでした。私は彼の質問についてより具体的にするために私の答えを編集する...申し訳ありません、私の間違い!私は次回にもっと注意するだろう... – marianobianchi

関連する問題