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...
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.
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
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.filter
also return Queryset.
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.
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.
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, everyone
is a queryset, and active_not_deleted
and active_is_deleted
are Python lists of User objects. The everyone
queryset will only be evaluated once in the first list(everyone)
call, and then the results are cached.
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)
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))
Answer for your comment,
Using Q or not, it has same raw query.
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.
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. user
and not_deleted
variables 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.