查询后可以过滤查询集吗? Django的

时间:2017-07-21 02:48:28

标签: python mysql django postgresql

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

例如这里......

 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_deletedis_deleted他们都有效,这与everyone相同是否可以使用everyone然后以某种方式筛选出is_deleted=Trueis_deleted=False?那么我相信如果可能的话,查询会更快更好吗?

然后,所有三个变量everyonenot_deletedis_deleted将被用于其他内容。

希望我能清楚明白我的问题。

提前致谢。

4 个答案:

答案 0 :(得分:11)

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

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中进行过滤。请注意,您无法对列表进行后续过滤,因为它们不是QuerySets。

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_deletedactive_is_deleted是用户对象的Python列表。 everyone查询集仅在第一次list(everyone)调用中评估一次,然后缓存结果。

答案 1 :(得分:1)

1。链过滤方法

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

@Cory Madden已经回答了。 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)

不会给你性能差异。

Queryset很懒。 usernot_deleted个变量只有queryset字符串。当您定义上面的变量时,它不会立即命中数据库。无论如何,你会为每个变量点击三次。

答案 2 :(得分:0)

你能做的最好的事情是:

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

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

答案 3 :(得分:0)

您可以根据需要过滤Queryset,因为filter()会返回一个新的Queryset,因此在过滤后您将获得过滤后的Queryset,您可以执行过滤或命令以及另一个methods that return new QuerySets

所以你可以这样做:

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。