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.

+3


source to share


4 answers


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:



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.

+5


source


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 might be yes if I understand it correctly.

0


source


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.

0


source


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.

0


source







All Articles