web-dev-qa-db-ja.com

クエリ後にクエリセットをフィルタリングすることは可能ですか? django

質問が奇妙に聞こえる場合は申し訳ありません。クエリセットを既に持っているときに新しいクエリセットを作成できるかどうか疑問に思っています。

ここに例があります...

 everyone = User.objects.filter(is_active=True)  # this would of course return all users that's active
 not_deleted = User.objects.filter(is_active=True, is_deleted=False)  # return user that's active and not deleted
 is_deleted = User.objects.filter(is_active=True, is_deleted=True)  # return user that's active and is already deleted

私の質問は... not_deletedおよびis_deleted両方ともアクティブであるeveryoneと同じであるeveryoneを使用し、何らかの方法でis_deleted=Trueまたはis_deleted=False?それで、これが可能であれば、クエリはより速く、より良くなると思いますか?

3つの変数すべてeveryonenot_deletedおよびis_deletedは、他の何かに使用されます。

うまくいけば、私の質問を静かに明確にした。

前もって感謝します。

13
Dora

はい、既存のクエリセットを再利用できます。

_everyone = User.objects.filter(is_active=True)
active_not_deleted = everyone.filter(is_deleted=False)
active_is_deleted = everyone.filter(is_deleted=True)
_

これは実際には速くなりませんが、実際、このコードブロックはDjango QuerySetsが遅延評価されるため、データベースに対してクエリを実行することさえしません。実際に値が必要になるまでデータベースにクエリを送信しますデータベースと通信する例を次に示します。

_everyone = User.objects.filter(is_active=True)  # Building SQL...
active_not_deleted = everyone.filter(is_deleted=False)  # Building SQL...
active_is_deleted = everyone.filter(is_deleted=True)  # Building SQL...

# Example of the whole queryset being evaluated
for user in everyone:
    # This will execute the query against the database to return the list of users
    # i.e. "select * from user where is_active is True;"
    print(user)

# Example of using iterator to evaluate one object at a time from the queryset.
for user in active_not_deleted.iterator():
    # This will execute the query for each result, so it doesn't
    # load everything at once and it doesn't cache the results.
    # "select * from user where is_active is True and is_deleted is False limit 1 offset 0;"
    # The offset is incremented on each loop and another query is sent to retrieve the next user in the list.
    print(user)
_

読むことをお勧めします:

この答えに加えて、単一のクエリを作成してからPythonでフィルタリングすることもできます。本当に必要な場合。クエリセットではないため、リストの後続のフィルタリングはできません。

_everyone = User.objects.filter(is_active=True)
active_not_deleted = list(filter(lambda user: user.is_deleted is False), list(everyone))
active_is_deleted = list(filter(lambda user: user.is_deleted is True), list(everyone))
_

この最後の例では、everyoneはクエリセットであり、_active_not_deleted_と_active_is_deleted_はPython Userオブジェクトのリストです。everyoneクエリセットは最初のlist(everyone)呼び出しで一度だけ評価され、その後、結果がキャッシュされます。

14
A. J. Parr

できる最善の方法は次のとおりです。

active_users = User.objects.filter(active=True)
not_deleted = active_users.filter(is_deleted=False)
deleted = active_users.filter(is_deleted=True)

したがって、あなたの質問に対する答えは、私がそれを正しく理解していればイエスかもしれません。

2
Cory Madden

1.チェーンフィルター方式

_not_deleted = User.objects.filter(active=True).filter(is_deleted=False)
_

@コリー・マッデンはすでに答えました。 User.objects.filter(active=True)はQuerysetを返します。そのため、フィルターメソッドを追加できます。 active_users.filter(is_deleted=False)

2. Qメソッドの使用

_from Django.db.models import Q

not_deleted = User.objects.filter(Q(active=True) & Q(is_deleted=False)
_

複雑なクエリセットを管理する方が簡単です。 userIDが3ではないことをフィルタリングする場合はどうなりますか? User.objects.filter(Q(active=True) & ~Q(id = 3))のようにQを使用できます


あなたのコメントに答え、

Qを使用してもしなくても、同じ生のクエリがあります。

_SELECT ... FROM ... 
WHERE ("auth_user"."active" = True AND "auth_user"."is_deleted" = False)
_

データベースのパフォーマンスは、データを抽出するためにデータベースにアクセスする頻度、またはFK関係によって何かを抽出するときに「結合」などの重い方法を使用する場合に関係します。したがって、Qを使用しても、クエリ文が同じであるため、パフォーマンスの違いは生じません。

さらに、

_user = User.objects.filter(active=True)
not_deleted = User.objects.filter(active=True).filter(is_deleted=False)

user = User.objects.filter(active=True)
not_deleted = user.filter(is_deleted=False)
_

パフォーマンスの違いはありません。

クエリセットは遅延しています。 userおよび_not_deleted_変数にはクエリセット文字列のみがあります。上記のように変数を定義しても、すぐにはデータベースにヒットしません。とにかく、変数ごとに3回ヒットします。

1
Jayground

filter()は新しいQuerysetを返すため、Querysetを必要なだけフィルタリングできます。フィルタリング後にQuerysetをフィルタリングし、filterまたはorderbyおよび別の メソッドを実行できます。新しいクエリセットを返します

だからあなたはこれを行うことができます:

active = User.objects.filter(active=True)
deleted = active.filter(is_deleted=True)
not_deleted = active.filter(is_deleted=False)

それはすべてUser.objects-QuerysetおよびUser.objects.filterもQuerysetを返します。

0
Vladyslav