[Answered ]-How does values_list django work?

1👍

The issue you’re seeing is likely due to the fact that Django QuerySet values_lists return generators. Since 1.9, QuerySet.values_list implements an iterable class like FlatValuesListIterable Prior to 1.9, QuerySet.values_list returned an instance of ValuesListQuerySet… Both of these return a generator, so the query is executed each time you access the variable (hence the behavior you were seeing when calling print).

The resulting object will behave a lot like a list, which is confusing, but if you need proof it’s not a list, try this:

from_values_ids = TestObject.objects.filter(value=value_1).values_list('id', flat=True)
from_list_ids = [obj.id for obj in TestObject.objects.filter(value=value_1)]
combined_list = from_values_ids + from_list_ids

… this will result in:

TypeError: unsupported operand type(s) for +: 'ValuesListQuerySet' and 'list'

The solution is simply to cast your from_values_ids variable as a list:

from_values_ids = list(TestObject.objects.filter(value=value_1).values_list('id', flat=True))

or just generate the list yourself:

from_values_ids = [obj.id for obj in TestObject.objects.filter(value=value_1)]

1👍

Your understanding is correct. Django querysets are lazy.

from_values_ids = TestObject.objects.filter(value=value_1).values_list('id', flat=True) # doesn't hit the db

to_values_ids = TestObject.objects.filter(value=value_2).values_list('id', flat=True) # doesn't hit the db

Now when you do:

TestObject.objects.filter(id__in=from_values_ids).update(value=value_2)
                                   |                  
                                   |__> will fetch from db 

Now all the values that matched value_1 got updated to value_2. Now next line is executed:

TestObject.objects.filter(id__in=to_values_ids).update(value=value_1)
                                      |
                                      |__> Will actually execute the query you assigned it
                 # TestObject.objects.filter(value=value_2).values_list('id', flat=True)

At this moment all the objects that match value_2 are fetched and updated to value_1

But you see no difference because you have all value_1 in the database before starting. Hence from_values_ids fetches all the objects and updates them to value_2 and then back to value_1. See having a mix of value_1 and value_2 records in the database. The difference will be evident.

Leave a comment