【问题标题】:Efficient way to update multiple fields of Django model object更新Django模型对象的多个字段的有效方法
【发布时间】:2017-06-04 06:54:57
【问题描述】:

我正在尝试更新 Django 数据库中的用户。

获取的数据如下:

fetched_data = {
     'id': 1,
     'first_name': 'John',
     'last_name': 'Doe',
     'phone': '+32 12',
     'mobile_phone': '+32 13',
     'email': 'myemail@hotmail.com',
     'username': 'myusername'
}

我得到这个 id 的用户如下:

old_user = User.objects.get(pk=fetched_data['id'])

如果我按如下方式更新用户:

old_user.username = fetched_data['username']
old_user.first_name = fetched_data['first_name']
......
old_user.save()

它工作正常,但我不想对每条记录都这样做,因此我尝试了类似的方法:

for fetched_data_key in fetched_data:
    old_user.fetched_data_key = fetched_data['fetched_data_key']
    //old_user[fetched_data_key] = fetched_data['fetched_data_key'] --- I tried this way to
    old_user.save()

但这不起作用。知道如何在不为每条记录都更新的情况下更新用户吗?

【问题讨论】:

    标签: python django


    【解决方案1】:
    setattr(old_user, fetched_data_key, fetched_data['fetched_data_key'])
    

    【讨论】:

      【解决方案2】:

      如果您使用QuerySet 对象的.update() 方法,则更简单:

      my_id = fetched_data.pop('id')  # remove 'id' from `fetch_data`
                                      # as it is not supposed to be updated
      
      User.objects.filter(pk=my_id).update(**fetched_data)
      #          unpack the content of `dict` ^
      

      它将解压fetched_data dict 的内容,并将User 对象中的记录更新为fetched_data dict。由于您在pk 上调用过滤器,因此它将始终返回单条记录。

      【讨论】:

      • 如果我只需要更新查询集中的一个对象怎么办?
      • "pk" 是 Django 模型中的唯一键。基于它的过滤将返回一个只包含一个对象的查询集。
      • 问题是我没有使用'pk'
      • @brainLoop : 默认情况下,“pk”引用 Django 模型的主键列。
      • @Anonymous 我和你解释的完全一样。记录已更新,但我的 updated_at (auto_now) 字段未更新。可能是因为我们不做Obj.save()
      【解决方案3】:

      您可以在不获取和反序列化的情况下更新数据库中的行; update() 可以。例如:

      User.objects.filter(id=data['id']).update(email=data['email'], phone=data['phone'])
      

      这将发出一条 SQL update 语句,并且比您帖子中的代码快得多。它永远不会获取数据或浪费时间创建User 对象。

      但是,您不能将一大堆更新数据发送到 SQL 数据库并要求它一次性将其映射到不同的行。如果您需要像这样快速完成的大规模更新,您最好的选择可能是将数据插入到单独的表中,然后update it form a select on that table。据我所知,Django ORM 不支持这一点。

      【讨论】:

      • 创建对象时,我知道您可以执行e = User(**data) 之类的操作。这对更新有用吗?
      • @DjangoBlockchain:可能,但它会破坏这个答案的目的。这个想法是为您要更新的每个数据库记录创建一个 ORM 模型对象。它真的会影响性能。
      • 我最终做了User.objects.filter(id=data['id']).update(**data),所以它只是更新每个字段而不是指定单个字段。抱歉,如果我的问题令人困惑。
      【解决方案4】:

      如果您使用.update 则会出现问题,因为它不会引发 post_savepre_save 信号,所以如果您想在任何更改数据然后User.objects.filter(pk=fetched_data['id']).update(**kwargs) 将不起作用。

      因此,您可以使用setattr() 更新字段,然后.save 将保存更新行的行也会引发信号。

      old_user = User.objects.get(pk=fetched_data['id'])
      for key, value in fetched_data.iteritems():
          setattr(old_user, key, value)
      old_user.save()
      

      【讨论】:

      • 这是迄今为止最好的方法。在所有大中型 Django 项目中,信号无处不在;你不想修补它们
      【解决方案5】:

      黑引号

      def update_block(request, id):

      a = RentedNumberBlock.objects.get(id=id)
      b = RentedNumber.objects.filter(user=request.user)
      c = a.rented_number.values_list('id', flat=True)
      if request.POST:
          update = RentedNumberBlock.objects.get(id=id)
          update.name = request.POST['name']
          z = dict(request.POST)['rented_number']
          y = RentedNumber.objects.filter(id__in=z)
          update.rented_number.set(z)
          update.save()
          return HttpResponseRedirect('/block/')
      return render(request, "block/update.html", {"a": a , "b": b, "c": c})
      

      【讨论】:

      • 您好,欢迎来到 Stack Overflow!请拨打tour。感谢您提供答案,但您是否还可以添加有关您的代码如何解决问题的解释?如果您在格式化方面需要帮助,请参阅help center
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-04
      • 2010-12-07
      • 2014-01-20
      • 1970-01-01
      • 2012-12-23
      • 2020-08-13
      相关资源
      最近更新 更多