[英]How does values_list django work?
I have interesting experience with value_list
and I don't know why is it acting in this way. 我在value_list
有有趣的经验,但我不知道为什么这样做。
I want to update any value in TestObject
has value_1
to value_2
and any value_2 to value_1. 我想更新TestObject
任何值,其中value_1
值为value_2
而value_2的值为value_1。 Where value_1
and value_2
from type Value and TestObject
has a foreign key to Value. 其中类型Value和TestObject
value_1
和value_2
具有Value的外键。
This is my code: 这是我的代码:
def _swap(value_1, value_2):
from_values_ids = TestObject.objects.filter(value=value_1).values_list('id', flat=True)
to_values_ids = TestObject.objects.filter(value=value_2).values_list('id', flat=True)
TestObject.objects.filter(id__in=from_values_ids).update(value=value_2)
TestObject.objects.filter(id__in=to_values_ids).update(value=value_1)
I tested with TestObject has value_1
but does not have any value_2
. 我测试过的TestObject具有value_1
但没有任何value_2
。 The end result was nothing happened after running this function. 运行此功能后,最终结果没有任何反应。 After investigating I found the TestObject got updated to value_2
after running: 经过调查,我发现运行后TestObject已更新为value_2
:
TestObject.objects.filter(id__in=from_values_ids).update(value=value_2)
but it returned back after running 但跑完后又回来了
TestObject.objects.filter(id__in=to_values_ids).update(value=value_1)
I thought may be to_values_ids
has lazy load that is why I added print to_values_id
. 我以为可能to_values_ids
具有延迟加载,这就是为什么我添加了print to_values_id
。
def _swap(value_1, value_2):
from_values_ids = TestObject.objects.filter(value=value_1).values_list('id', flat=True)
to_values_ids = TestObject.objects.filter(value=value_2).values_list('id', flat=True)
print to_values_ids
TestObject.objects.filter(id__in=from_values_ids).update(value=value_2)
TestObject.objects.filter(id__in=to_values_ids).update(value=value_1)
But I got the same result. 但是我得到了相同的结果。 Although my print for to_values_ids
has []
. 尽管我打印的to_values_ids
具有[]
。
The way I fix it I created new lists with the ids and it worked but still needs to understand the core python how is it work? 我修复它的方式是用id创建了一个新列表,它起作用了,但仍然需要了解核心python的工作原理? Any good explanation. 任何好的解释。
Your understanding is correct. 您的理解是正确的。 Django querysets are lazy . Django查询集是惰性的 。
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
. 现在,所有与value_1
匹配的值都更新为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
此时,所有与value_2
匹配的对象均被提取并更新为value_1
But you see no difference because you have all value_1
in the database before starting. 但是您看不出有什么区别,因为在启动之前数据库中所有值都为value_1
。 Hence from_values_ids
fetches all the objects and updates them to value_2
and then back to value_1
. 因此from_values_ids
获取所有对象,并将它们更新为value_2
,然后再返回为value_1
。 See having a mix of value_1
and value_2
records in the database. 请参见在数据库中混合使用value_1
和value_2
记录。 The difference will be evident. 差异将显而易见。
The issue you're seeing is likely due to the fact that Django QuerySet values_lists return generators. 您看到的问题很可能是由于Django QuerySet values_lists返回生成器。 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). 从1.9开始, QuerySet.values_list
实现一个类似于FlatValuesListIterable的可迭代类。在1.9之前, QuerySet.values_list
返回了ValuesListQuerySet的一个实例。这两个实例都返回一个生成器,因此每次访问变量时都会执行查询(因此,您的行为在调用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
变量转换为列表:
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)]
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.