代码之家  ›  专栏  ›  技术社区  ›  Jerry

Django Questle设置索引洗牌,不记得我的变化

  •  1
  • Jerry  · 技术社区  · 6 年前

    背景

    我有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中,它有一堆日期字段,如下所示

    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] cs[3] . 只有4条记录。现在我想将一个nullBooleanField改为false/true。我做的 cs[1].foo = true cs[1].save()

    我希望4条记录的顺序与获取它们时的顺序相同,并且第二条记录的foo字段将被更新。

    实际结果是,由于某些原因,第二条记录被移到列表的后面,它不记得我的更改。

    例如,在开头,有4条记录是R1、R2、R3、R4,R2.foo为false。在如上所述将第二条记录的foo指定为true之后,结果是R1、R3、R4、R2和R2。foo仍然为false。

    解决方法似乎是先将cs[1]分配给变量,然后再更改变量。知道原因就好了。

    Django中是否有任何东西可以导致queryset结果重新排列?

    编辑 每个queryset[索引]都会导致数据库命中吗?

    1 回复  |  直到 6 年前
        1
  •  1
  •   willeM_ Van Onsem    6 年前

    问题 : qs 是一个 QuerySet . 如果你写信 qs[i] ,你实际上 另一个问题 (看起来像 <OLD QUERY> LIMIT 1 OFFSET i ),所以你把 -这个元素从旧的queryset进入内存。

    关键是如果你写 质量标准[i] 两次,两次 独立的 抓取。如果我们这样写两个 qs[1] s、 我们得到两个 不同的 物体。如果你这样做 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

    在许多数据库引擎中,两个查询之间对象的顺序改变是很常见的(通常给定一些行被更新,或者即使创建了一个新行)。这取决于数据库如何获取行的索引,并且通常更改的行将作为结果集中的最后(或第一)行出现,尽管如果不指定顺序,通常没有 坚强的 保证结果如何排序。