Python 可以在查询后过滤查询集吗?姜戈

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/45228187/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-19 16:50:35  来源:igfitidea点击:

possible to filter the queryset after querying? django

pythonmysqldjangopostgresql

提问by Dora

Sorry if the question sounds weird. I am just wondering if there is possible to make new queryset when I already have a queryset.

对不起,如果问题听起来很奇怪。我只是想知道当我已经有一个查询集时是否可以创建新的查询集。

For example here...

例如这里...

 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

What my question is...for not_deletedand is_deletedthey both have active is true with is the same as everyoneis there a possible way to use everyoneand then somehow filter out is_deleted=Trueor is_deleted=False? So then I believe the querying would be faster and better if this is possible right?

我的问题是什么?对于not_deletedis_deleted他们都有积极作为是相同真正everyone有使用一个可能的方式everyone,然后以某种方式过滤掉is_deleted=Trueis_deleted=False?那么我相信如果这是可能的,查询会更快更好吗?

All three variables everyone, not_deletedand is_deletedwill then be used for something else.

所有这三个变量everyonenot_deleted并且is_deleted将被用于别的东西。

Hopefully I made my question quiet clear.

希望我把我的问题说清楚了。

Thanks in advance.

提前致谢。

回答by A. J. Parr

Yes, you can reuse existing querysets.

是的,您可以重用现有的查询集。

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

This is not really making anything faster though, in fact, this code block won't even execute a query against the database because Django QuerySets are lazily evaluated. What I means is that it won't send the query to the database until you actually need the values. Here's an example that will talk to the database.

虽然这并没有真正使任何事情变得更快,但事实上,这个代码块甚至不会对数据库执行查询,因为 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)

Recommend reading:

推荐阅读:

As an addition to this answer, you could make a single query and then filter in Python if you really wanted. Mind you, you could not do subsequent filtering on the lists because they are not QuerySets.

作为此答案的补充,您可以进行单个查询,然后根据需要在 Python 中进行过滤。请注意,您无法对列表进行后续过滤,因为它们不是 QuerySet。

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

In this last example, everyoneis a queryset, and active_not_deletedand active_is_deletedare Python lists of User objects. The everyonequeryset will only be evaluated once in the first list(everyone)call, and then the results are cached.

在最后一个示例中,everyone是一个查询集,active_not_deleted并且active_is_deleted是用户对象的 Python 列表。查询集everyone只会在第一次list(everyone)调用中评估一次,然后缓存结果。

回答by Cory Madden

The best you can do is:

你能做的最好的是:

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

So the answer to your question may be yes, if I understand it correctly.

所以你的问题的答案可能是肯定的,如果我理解正确的话。

回答by Jayground

1. chain filter method

1. 链式过滤法

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

@Cory Madden already answered. User.objects.filter(active=True)returns Queryset. So you can add filter method. active_users.filter(is_deleted=False)

@Cory Madden 已经回答了。User.objects.filter(active=True)返回查询集。所以你可以添加过滤方法。active_users.filter(is_deleted=False)

2. using Q method

2.使用Q方法

from django.db.models import Q

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

It is easier to manage your complicated queryset. What if you want to filter userID is not 3? you can use Q simplye like User.objects.filter(Q(active=True) & ~Q(id = 3))

管理复杂的查询集更容易。如果要过滤userID不是3怎么办?您可以使用 Q simplee 之类的User.objects.filter(Q(active=True) & ~Q(id = 3))



Answer for your comment,

回答你的评论,

Using Q or not, it has same raw query.

无论是否使用 Q,它都有相同的原始查询。

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

Database performance is relating to how often you hit database to extract data or if you use a heavy method like 'Join' when you extract something by FK relationship. So Using Q or not doesn't give you performance difference, because it has same query sentence.

数据库性能与您访问数据库以提取数据的频率有关,或者当您通过 FK 关系提取某些内容时是否使用了像“加入”这样的繁重方法。所以使用 Q 与否不会给您带来性能差异,因为它具有相同的查询语句。

Additionally,

此外,

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)

would not give you performance difference.

不会给你性能差异。

Queryset is lazy. userand not_deletedvariables have just queryset string. It doesn't hit the database right away when you define variable like above. Anyway, you will hit three times for each variable.

查询集是懒惰的。usernot_deleted变量只有查询集字符串。当您像上面一样定义变量时,它不会立即访问数据库。无论如何,您将为每个变量击中 3 次。

回答by Vladyslav

You can filter Queryset so much time that you want, because filter()returns a new Queryset so after filtering you get filtered Queryset and you can do filter or orderby and another methods that return new QuerySets

您可以根据需要过滤 Queryset,因为会filter()返回一个新的 Queryset,因此在过滤后您会得到过滤的 Queryset,您可以执行 filter 或 orderby 以及其他返回新 QuerySets 的方法

So you can do this:

所以你可以这样做:

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

All it is because User.objects- is Queryset and User.objects.filteralso return Queryset.

这一切都是因为User.objects- 是 Queryset 并且User.objects.filter还返回 Queryset。