简体   繁体   English

values_list django如何工作?

[英]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_1value_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_1value_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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM