2017-02-03 33 views
1

我有value_list有趣的經驗,我不知道爲什麼它以這種方式行事。values_list django如何工作?

我想更新TestObject中的任何值,其中value_1value_2,任何value_2值爲value_1。其中value_1value_2來自Value並且TestObject具有Value的外鍵。

這是我的代碼:

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) 

我的TestObject試驗時,有value_1,但沒有任何value_2。 運行此功能後,最終結果沒有任何發生。經過調查,我發現的TestObject得到運行後更新爲value_2

TestObject.objects.filter(id__in=from_values_ids).update(value=value_2) 

但它運行

TestObject.objects.filter(id__in=to_values_ids).update(value=value_1) 

我想之後返回可能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) 

但是我得到了同樣的結果。雖然我的打印to_values_ids[]

我解決這個問題,我創建一個新的列表與IDS和它的工作,但仍然需要了解核心Python中是如何工作的呢?任何好的解釋。

+0

嘗試打印兩者。如果你的'to_values_ids = []'這意味着你沒有更新任何東西! –

+0

兩次更新之前的列表to_values_ids是空的,但在運行TestObject.objects.filter(id__in = from_values_ids).update(value = value_2)後,它已更改。爲什麼會發生? – amm

+0

'QuerySets'作爲值返回,而不是引用,所以不應該發生...... –

回答

1

您遇到的問題可能是由於一個事實,即Django的查詢集values_lists回報發電機。由於1.9,QuerySet.values_list實現像FlatValuesListIterable此前1.9迭代類,QuerySet.values_list返回一個實例的ValuesListQuerySet ......這兩個返回一個發電機,所以查詢每次訪問變量時執行(因此你的行爲打電話時看到了打印)。

產生的對象的行爲很像一個列表,這是混亂的,但如果你需要證明它不是一個列表,試試這個:

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 

...這將導致:

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

的解決方案是簡單地投你from_values_ids變量列表:

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

或只是自己生成列表:

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

你的理解是正確的。 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 

現在,當你這樣做:

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

現在所有匹配value_1價值得到了更新,以value_2。現在,下一行執行:

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) 

此時匹配value_2是獲取和更新,以value_1

的所有對象,但你看到的沒有什麼區別,因爲你開始之前,必須在數據庫中的所有value_1。因此from_values_ids獲取所有對象並將其更新爲value_2,然後回到value_1。請參閱在數據庫中混合使用value_1value_2記錄。差異將是顯而易見的。

+0

非常感謝您的回覆!但是當我現在調用print時,它應該用[]加載to_values_ids,但是在運行第一次更新之後它會被更新。所以它不僅僅是延遲加載它已經被再次更新,我不明白。 – amm

+2

@amm打印查詢集僅查詢查詢集的前20個元素。由於這可能不是整個查詢集,因此它不會被緩存。即使它是整個查詢集,也會選擇一致性而不是優化,而且查詢集不會被緩存。如果迭代查詢集或調用'list()','len()'或'bool()',則整個查詢集將被計算和緩存。 – knbk