我想用Django更新一个表 - 类似于在原始SQL中执行以下操作:
update tbl_name set name = 'foo' where name = 'bar'
我的第一个结果是这样的 - 但那很讨厌,不是吗?
list = ModelClass.objects.filter(name = 'bar')
for obj in list:
obj.name = 'foo'
obj.save()
有更优雅的方法吗?
我想用Django更新一个表 - 类似于在原始SQL中执行以下操作:
update tbl_name set name = 'foo' where name = 'bar'
我的第一个结果是这样的 - 但那很讨厌,不是吗?
list = ModelClass.objects.filter(name = 'bar')
for obj in list:
obj.name = 'foo'
obj.save()
有更优雅的方法吗?
Django 2.2版本现在有一个bulk_update方法。
请参考以下django文档部分。
简单来说,你应该能够使用:
ModelClass.objects.filter(name='bar').update(name="foo")
你也可以使用F
对象来执行一些操作,例如递增行:
from django.db.models import F
Entry.objects.all().update(n_pingbacks=F('n_pingbacks') + 1)
请参阅文档。
但是,请注意:
ModelClass.save
方法(因此,如果其中有某些逻辑,则不会触发它)。.update()
操作,必须在原始QuerySet上进行,因此您需要依赖于.filter()
和.exclude()
方法。save()
方法,具有auto_now=True
选项(也称为“修改时间”列)的DateTimeField
字段将无法更新。 - ArthurModelClass.objects.filter(name='bar').update(name="foo")
这个方法就不能实现批量更新的目的。那么,如果不想使用循环,该怎么做呢? - ShashankEntry.objects.all().update(title=F('blog__title'))
。文档中有一个小小的提及。
如果您想从另一个模型中提取数据来更新条目,您将不得不运行一个for循环。 - sean.hudsonbulk_update
的 batch_size
参数。 - Jill-Jênn Vie考虑使用在GitHub上找到的django-bulk-update
。
安装: pip install django-bulk-update
实现: (代码直接取自项目的ReadMe文件)
from bulk_update.helper import bulk_update
random_names = ['Walter', 'The Dude', 'Donny', 'Jesus']
people = Person.objects.all()
for person in people:
r = random.randrange(4)
person.name = random_names[r]
bulk_update(people) # updates all columns using the default db
更新:正如Marc在评论中指出的那样,这不适合一次更新数千行。虽然它适用于更新10到100个较小的批次。适合您的批处理大小取决于您的CPU和查询复杂性。这个工具更像是手推车而不是倾卸卡车。
Django 2.2版本现在有一个bulk_update
方法(发布说明)。
https://docs.djangoproject.com/en/stable/ref/models/querysets/#bulk-update
示例:
# get a pk: record dictionary of existing records
updates = YourModel.objects.filter(...).in_bulk()
....
# do something with the updates dict
....
if hasattr(YourModel.objects, 'bulk_update') and updates:
# Use the new method
YourModel.objects.bulk_update(updates.values(), [list the fields to update], batch_size=100)
else:
# The old & slow way
with transaction.atomic():
for obj in updates.values():
obj.save(update_fields=[list the fields to update])
我在互联网上发现了有关上述问题的有用内容
https://www.sankalpjonna.com/learn-django/running-a-bulk-update-with-django
低效的方法
model_qs= ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
obj.name = 'foo'
obj.save()
高效的方式
ModelClass.objects.filter(name = 'bar').update(name="foo") # for single value 'foo' or add loop
使用bulk_update
update_list = []
model_qs= ModelClass.objects.filter(name = 'bar')
for model_obj in model_qs:
model_obj.name = "foo" # Or what ever the value is for simplicty im providing foo only
update_list.append(model_obj)
ModelClass.objects.bulk_update(update_list,['name'])
使用原子事务
from django.db import transaction
with transaction.atomic():
model_qs = ModelClass.objects.filter(name = 'bar')
for obj in model_qs:
ModelClass.objects.filter(name = 'bar').update(name="foo")
有人点赞吗?提前感谢:感谢您关注;)
User.objects.bulk_update([User(id=k, score=v) for k, v in user_ids_dict.items()], ['score'])
即可... - jerch如果你想在一组行中设置相同的值,你可以使用update()方法结合任何查询条件来更新所有行:
some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)
如果你想根据某些条件更新一组不同值的行集合,你可以批量更新这些值。比如说你有1000行数据需要将一列设置为X个值中的一个,那么你可以事先准备好批次,然后只运行X次更新查询(每次查询基本上与上面的第一个示例具有相同的形式),加上初始的SELECT查询。
如果每行需要一个独特值,那么避免每个更新操作至少需要一个查询是无法避免的。也许在后一种情况下,你需要考虑其他架构,比如CQRS/事件溯源,以获得更好的性能。
要更新相同的值,我们可以简单地使用以下方法
ModelClass.objects.filter(name = 'bar').update(name='foo')
更新不同的值
ob_list = ModelClass.objects.filter(name = 'bar')
obj_to_be_update = []
for obj in obj_list:
obj.name = "Dear "+obj.name
obj_to_be_update.append(obj)
ModelClass.objects.bulk_update(obj_to_be_update, ['name'], batch_size=1000)
它不会每次都触发保存信号,而是将所有需要更新的对象保存在列表中,并一次性触发更新信号。
ModelClass.objects.filter(name='bar').update(name = '亲爱的 ' + F('name'))
- jerchIT返回表中更新的对象数量。
update_counts = ModelClass.objects.filter(name='bar').update(name="foo")
现在,QuerySet.bulk_create()支持在行插入失败唯一性约束时更新字段。这在MariaDB、MySQL、PostgreSQL和SQLite 3.24+上都受支持。