Can I filter the request after the request? Django
Sorry if the question sounds strange. I'm just wondering if there is an option to make a new request when I already have a request.
For example, here ...
everyone = User.objects.filter(is_active=True) # this would of course return all users that active
not_deleted = User.objects.filter(is_active=True, is_deleted=False) # return user that active and not deleted
is_deleted = User.objects.filter(is_active=True, is_deleted=True) # return user that active and is already deleted
What is my question, for not_deleted
and is_deleted
they both are true, is the same as everyone
, is there a way to use everyone
and then filter somehow is_deleted=True
or is_deleted=False
? So I suppose the query would be faster and better if possible?
All three variables everyone
, not_deleted
and is_deleted
will then be used for something else.
I hope I made my question calm.
Thanks in advance.
source to share
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)
It doesn't actually make anything faster, although in fact this block of code doesn't even execute a database query because Django QuerySets are lazy evaluated. I mean, it won't send a query to the database until you need the values. Here's an example that will work with a 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)
We recommend reading:
- https://docs.djangoproject.com/en/1.11/topics/db/queries/#querysets-are-lazy
- https://docs.djangoproject.com/en/1.11/ref/models/querysets/#iterator
- https://docs.djangoproject.com/en/1.11/topics/db/queries/#caching-and-querysets
As a complement to this answer, you can make one request and then filter in Python if you like. Be aware that you cannot perform post-filtering on 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, it everyone
is a set of queries, and active_not_deleted
and active_is_deleted
are lists of Python objects of User objects. The query request everyone
will be evaluated only once in the first call list(everyone)
, and then the results will be cached.
source to share
You can filter the Queryset as long as you want because it filter()
returns a new Queryset, so after filtering, you get a filtered Queryset and you can do a filter or orderby and another one that returns 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)
This is because it User.objects
is a Queryset and User.objects.filter
also returns a Queryset.
source to share
1 chain filter method
not_deleted = User.objects.filter(active=True).filter(is_deleted=False)
@ Corey Madden already answered. User.objects.filter (active = True) returns Queryset. This way you can add filtering method. active_users.filter (is_deleted = False)
2 using the Q method
from django.db.models import Q
not_deleted = User.objects.filter(Q(active=True) & Q(is_deleted=False)
easier to manage a complex set of queries. What if you want to filter out user id not 3? you can use Q simplee likeUser.objects.filter(Q(active=True) & ~Q(id = 3))
reply to your comment,
Using Q or not, it has the same raw query.
SELECT ... FROM ...
WHERE ("auth_user"."active" = True AND "auth_user"."is_deleted" = False)
Database performance has to do with how often you go to the database to fetch data or use a heavy method like "Join" when you fetch something over FK relationships. So, using Q or not doesn't give you a performance difference because it has the same sentence of the sentence.
Besides,
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)
won't give you a performance difference.
queryset is lazy. user and not_deleted variables only have a queryset string. It doesn't go straight to the database when you define a variable like above. anyway, you will press three times for each variable.
source to share