2016-09-19 205 views
0

我有一個Django模型: -Django的過濾器保存查詢集

class ModelA(models.Model): 
    flag = models.BooleanField(default=True) 

接下來,我查詢它: -

obj = ModelA.objects.filter(flag=True)

現在,我改變第一個對象的flag

obj1 = obj[0] 
obj1.flag = False 
obj1.save() 

現在,當我再次得到obj[0],它返回我的過濾查詢的2nd object爲什麼?

+0

你怎麼知道它是第二個對象?你如何評價它?可能 - 這是問題,當您再次評估查詢集時,第二個對象成爲第一個匹配條件的對象? – karthikr

+0

我'打印'它。對象的'id'。 – PythonEnthusiast

+0

看看[首頁](https://docs.djangoproject.com/en/1.10/ref/models/querysets/#first) –

回答

-1

因爲第一個對象不再匹配過濾的查詢集,所以在obj指針中找不到它。如果您想將查詢集克隆到另一個變量,您可以使用values_list

+0

你的答案是不夠的。如果在修改其中一個項目之前迭代查詢集,則不會有此行爲... –

0

我相信每次運行obj[0]時,Django都會返回到數據庫並運行查詢。你可以看到,通過使用django.db.connection執行的查詢:

>>> from django.db import connection 

>>> obj = ModelA.objects.filter(flag=True) 
>>> print(connection.queries) 
[] 

>>> o = obj[0] 
>>> print(connection.queries) 
[{'time': '0.001', 'sql': 'SELECT "myapp_modela"."id", "myapp_modela"."flag" FROM "myapp_modela" WHERE "myapp_modela"."flag" = 1 LIMIT 1'}] 

>>> o.flag = False 
>>> o.save() 
>>> print(connection.queries) 
[{'time': '0.001', 'sql': 'SELECT "myapp_modela"."id", "myapp_modela"."flag" FROM "myapp_modela" WHERE "myapp_modela"."flag" = 1 LIMIT 1'}, 
{'time': '0.000', 'sql': 'BEGIN'}, 
{'time': '0.002', 'sql': 'UPDATE "myapp_modela" SET "flag" = 0 WHERE "myapp_modela"."id" = 1'}] 

>>> o = obj[0] 
>>> print(connection.queries) 
[{'time': '0.001', 'sql': 'SELECT "myapp_modela"."id", "myapp_modela"."flag" FROM "myapp_modela" WHERE "myapp_modela"."flag" = 1 LIMIT 1'}, 
{'time': '0.000', 'sql': 'BEGIN'}, 
{'time': '0.002', 'sql': 'UPDATE "myapp_modela" SET "flag" = 0 WHERE "myapp_modela"."id" = 1'}, 
{'time': '0.000', 'sql': 'SELECT "myapp_modela"."id", "myapp_modela"."flag" FROM "myapp_modela" WHERE "myapp_modela"."flag" = 1 LIMIT 1'}] 
+1

只有在resultcache爲空的情況下才會執行此操作 - 如果您沒有先遍歷查詢集。一旦開始迭代查詢集,它將填充它的'resultcache',然後後續的下標將只返回resultcache中的內容。 –

+0

不是開銷,再次查詢數據庫。 Isnt將查詢集轉換爲列表是一個好主意,列表(ModelA.objects。過濾(標誌=真))'? – PythonEnthusiast

0

如果你看看Queryset.__getitem__()(Django的/ DB /模型/ query.py),你會發現這(Django的1.10):

295 qs = self._clone() 
296 qs.query.set_limits(k, k + 1) 
297 return list(qs)[0] 

請注意,如果queryset尚未被迭代,那麼您只能到那裏 - 否則它會從它的resultcache中獲取實例,然後您將獲得相同的實例兩次。

FWIW,這段代碼的重點在於優化數據庫訪問(通過在單個實例被請求時不提取整個數據集),並且是的,至少可以這麼說。

如果你想要的是保持修改的第一個項目,同時仍保持其作爲數據集的一部分,你要使用整個數據集,最簡單的辦法是之前做出list從您的查詢集:

obj = list(ModelA.objects.filter(flag=True)) 
obj1 = obj[0] 
obj1.flag = False 
obj1.save()