背景
我让模型C继承了B
在C语言中,它只有普通的charField,nullBooleanField和外键。
class C(B):
uid = UUIDField(unique=True)
x = models.ForeignKey(X, to_field='uid')
y = models.ForeignKey(Y, to_field='uid', null=True)
z = models.TextField()
u = models.ForeignKey(U, null=True)
foo = models.NullBooleanField(default=False)
在B中,它具有如下所示的一堆dateField
class B(models.Model):
date_added = models.DateTimeField(auto_now_add=True)
date_modified = models.DateTimeField(auto_now=True)
date_deactivated = models.DateTimeField(null=True, blank=True)
active = models.BooleanField(default=True, db_index=True,
help_text='Set to false if the instance is deleted.')
class Meta:
abstract = True
这些类均未指定元顺序。
问题
当我在shell_plus中时,我将C.objects.all()
分配给名为cs
的变量,然后可以看到cs[0]
,cs[1]
,cs[2]
和{ {1}}。只有4条记录。现在,我想将一个nullBooleanField更改为false / true。我做了cs[3]
和cs[1].foo = true
我希望4条记录的顺序与我获取它们时的顺序相同,并且第二条记录的foo字段也会更新。
由于某些原因,实际结果是第二条记录移到了列表的后面,并且它不记得我的更改了。
例如,开头有4条记录,分别是R1,R2,R3,R4和R2.foo为false。如上所述,在为第二条记录分配foo为true之后,结果为R1,R3,R4,R2和R2。foo仍然为false。
解决方法似乎是先将cs [1]分配给变量,然后再更改变量。知道为什么会很好。
Django中是否有任何东西可能导致queryset结果重新排列?
修改 每个queryset [index]会导致数据库命中吗?
答案 0 :(得分:1)
问题:qs
是QuerySet
。如果您写qs[i]
,则实际上是另一个查询(一个看起来像<OLD QUERY> LIMIT 1 OFFSET i
的查询),因此您可以从中获取第 i 个元素旧查询集存入内存。
重点是,如果您两次写入qs[i]
,则会进行两次独立提取。如果我们这样写两个qs[1]
,我们将获得两个 different 对象。如果这样执行qs[1].save()
,则需要进行独立的访存,从数据库中加载对象,然后立即保存它。但是以前未保存的修改将无效。
如果因此要更改对象,则需要使用引用,因此请写:
# will change the second element
cs1 = cs[1] # we fetch the object, and store it in cs1
cs1.foo = True # we change the object
cs1.save() # we save the object
代替:
# will *NOT* change the second element
cs[1].foo = True # load object, change it, but throws the object away
cs[1].save() # loads the object again, and save it, with no change
对象的顺序在两个查询之间改变的事实在许多数据库引擎中很常见(通常给定某行已更新,或者即使创建了新行也是如此)。它取决于数据库具有如何获取行的索引,并且更改的行通常会出现在结果集中的最后一行(或第一行),尽管如果不指定顺序,通常不会出现 strong 保证结果的排序方式。