Values_list on EmptyQuerySet used in query filters returns a full set

Recently found something peculiar in the filter, I can not believe in its intended behavior.

from django.contrib.auth.models import User print User.objects.filter(id__in=User.objects.none().values_list("id",flat=True)) print User.objects.filter(id__in=User.objects.all().values_list("id",flat=True)) 

Oddly enough, both of these lists return a full set of users. Actually, it seems pretty easy to β€œfix” it if I close the internal query in a list function, for example.

 User.objects.filter(id__in=list(User.objects.none().values_list("id"))) 

Then it returns what I expect (empty list).

It seems to be a mistake, or am I missing something?

Steve

+6
source share
1 answer

Here are the queries created for both:

User.objects.filter (id__in = User.objects.none (). Values_list ("ID", flat = True))

 SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" IN (SELECT U0."id" FROM "auth_user" U0) LIMIT 21 

User.objects.filter (id__in = User.objects.all (). Values_list ("ID", flat = True))

 SELECT "auth_user"."id", "auth_user"."username", "auth_user"."first_name", "auth_user"."last_name", "auth_user"."email", "auth_user"."password", "auth_user"."is_staff", "auth_user"."is_active", "auth_user"."is_superuser", "auth_user"."last_login", "auth_user"."date_joined" FROM "auth_user" WHERE "auth_user"."id" IN (SELECT U0."id" FROM "auth_user" U0) LIMIT 21 

Notice something? These are exactly the same queries. It's also interesting what happens if you try things like User.objects.none() , User.objects.filter(id__in=[]) and User.objects.filter(id__in=User.objects.none() . In all three of these circumstances, Django closes the request. In other words, it doesn’t even issue the request to the database because it determines in advance that there will be no results. My best assumption is that adding values_list to the end values_list logic of the short circuit, allowing you to send the actual request and what values_list actually values_list is the request that should be sent. the case is really the same when you think about it, anyway you only want to select id for the unfiltered set of queries.

I emphasized this part because I am sure that you are now jumping up and down, but none should return an empty request. True, but he does this by virtue of the automatic return of EmptyQuerySet and never queries the database at all. It does not add any filters to the request.

Whether this is a mistake or not is debatable. I am more likely to call it the cornerstone, which most likely cannot be "fixed." This is a function of how all interwoven parts are combined into one script.

+1
source

Source: https://habr.com/ru/post/920962/


All Articles