2016-12-01 35 views
1

我試圖以原子方式更新查詢集的字段。我有這樣的事情:以原子方式更新查詢集中的每個實例

counter = 0 
for row in myQuerySet: 
    row.myField = counter 
    counter = counter + 1 
    row.save() 

這一工程,但我想原子做到這一點,因爲我有數百個寄存器,這是浪費時間。我需要這樣的事情:

counter = 0 
myQuerySet.update(myField=(counter+=1)) 

但這並不奏效。什麼是正確的sintax?

+1

更新語句創建單個SQL查詢,如果您使用的值不是表的一部分(即不是字段),它將被視爲常量,在這種情況下,所有行都將被更新值。 – AKS

+1

'F()'對象可以幫助更新基於現有字段值的字段,但我無法想到基於遞增的外部值更新字段的方法。 –

+0

@Sayse我有很多帶有「step_number」整數字段的寄存器。該字段可以手動更改,您可以獲得帶有間隙的增量序列,例如,如果您有5個寄存器,它們的step_numbers可以是1,2,3,8,9。但我想重新編號以獲得1,2,3,4,5序列。這是櫃檯的目的。 – MouTio

回答

2

這一工程,但我想原子做到這一點[...]

通常情況下,答案是使用QuerySet.update method。當你想對查詢集中的所有實例執行相同的操作時(或者不需要動態更改的時候),這是有效的。

由於您要執行的操作似乎需要依次對每個實例進行動態更改,因此可以改爲使用select_for_update method

from django.db import transaction 

dolors = LoremIpsum.objects.select_for_update().filter(dolor=True) 

with transaction.atomic(): 
    counter = 0 
    for lorem_ipsum in dolors: 
     lorem_ipsum.amet = counter 
     counter += 1 
     lorem_ipsum.save() 

documentation for select_for_update說,這你想要做什麼:

所有匹配條目將被鎖定,直到事務塊結束,這意味着其他事務將更改或對他們獲取鎖可防止。

因爲查詢集導致項目「被鎖定直到事務塊結束」,所以您需要使用上述的transaction.atomic在事務塊內執行操作。

+1

就是這樣!在select_for_update之前缺少了「對象」部分,我只會添加必須添加「with transaction.atomic()」(來自django.db導入事務),因爲select_for_update不能在事務之外使用。 – MouTio