2016-09-19 98 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()