【问题标题】:Django: Update multiple objects attributesDjango:更新多个对象属性
【发布时间】:2017-05-06 07:16:49
【问题描述】:

有没有更有效的方法可以用 F 表达式来做到这一点?一些如何减少打数据库?

# 1st way hits DB twice per object
def something():
  pks = [4, 2, 1, 3, 0]
  for i in range(len(pks)):
    mymodel.objects.get(pk=pks[i]).update(attr=i)

# 2nd way hits DB once per obj and once for the queryset
def something():
  pks = [4, 2, 1, 3, 0]
  order = Case(*[When(pk=pk, then=pos) for pos, pk in enumerate(pks)])
  query = mymodel.objects.filter(pk__in=pks).order_by(order)
  for i in range(len(query)):
    query[i].attr = i
    query[i].save()

编辑以使变量保持一致。

【问题讨论】:

    标签: python django django-orm


    【解决方案1】:

    通常要避免进行多个数据库查询而不是一个大型查询。但是,您的情况似乎是个例外。 (注意:我是根据提供的信息做出这个答案的。请不要编辑你的问题,说我实际上是说......)

    无论您有多少条记录,以下查询都将非常快,因为它从主键中检索单个项目。所有 RDBMS 都旨在很好地处理这个问题。

    mymodel.objects.get(pk=a[i]) 
    

    如何让你的函数更高效:

    def something():
      pks = [4, 2, 1, 3, 0]
      for i in range(len(a)):
        mymodel.objects.filter(pk=a[i]).update(attr=i)
    

    现在每个对象只命中数据库一次。上面的查询只是转换为

     UPDATE mapp_mymodel SET attr=i where pk=1
    

    【讨论】:

    • 你能解释一下get和filter的区别吗?您说 get 非常快,因为它正在检索项目但在您的代码中使用过滤器。如果我想要多个对象并获得一个对象,我通常会使用过滤器。
    • get 和 filter 的区别在于 get 获取一个对象,然后按照您的发现进行更新。过滤器实际上不会从数据库中检索任何内容,直到您从中获取切片或遍历它。
    • 我认为这会命中数据库 2 次,因为一次获取​​对象,然后再次更新所述对象。
    • 好的,我现在明白了!谢谢您的帮助!由于某种原因不得不制作多个 cmet。
    • 请参阅更新。 filter 并不比 get 快(或慢)。快速的是使用主键查询数据库。一般来说,你不必太担心重复这样的查询 4 ​​或 5 次
    【解决方案2】:

    如果我没记错的话,你可以这样做

    pks = [4, 2, 1, 3, 0]
    mymodel.object.filter(pk__in=pks).update(attr='test')
    

    除非您尝试使用 for 循环索引作为属性值,否则这是行不通的。

    【讨论】:

    • 根据 OP 的问题。当 pk=i, attr=i (每个 attr 不同)这就是为什么我在我的答案中添加了这个警告。在上面的查询中。所有实例的 attr=1
    • 认为可能是这种情况(因此答案的最后一行)。但张贴只是以防万一。你的回答似乎更有帮助。谢谢..
    • 是的,我使用索引作为 attr 的值。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-04
    • 1970-01-01
    • 2013-01-18
    • 2013-02-24
    • 2017-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多