我想用 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 执行 an ,它必须在原始 QuerySet 上,因此您需要依靠.filter()
and.exclude()
方法。考虑使用在 GitHub 上找到django-bulk-update
的。
安装:pip install django-bulk-update
实施:(代码直接取自项目自述文件)
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])
如果你想在一组 rows 上设置相同的值,你可以使用 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/事件溯源。
这是我在互联网上找到的关于上述问题的有用内容
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 obj in model_qs:
model_obj =ModelClass.object.get(id=obj.id)
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")
任何赞成票?提前致谢:感谢您的关注;)
要更新相同的值,我们可以简单地使用它
ModelClass.objects.filter(name = 'bar').update(name='foo')
使用不同的值进行更新
list = ModelClass.objects.filter(name = 'bar')
obj_to_be_update = []
for obj in list:
obj.name = "Dear "+obj.name
obj_to_be_update.append(obj)
ModelClass.objects.bulk_update(obj_update_list, ['name'], batch_size=1000)
它不会每次都触发保存信号,而是我们将所有要更新的对象保留在列表中并立即触发更新信号。
IT 返回的对象数量在表中更新。
update_counts = ModelClass.objects.filter(name='bar').update(name="foo")
您可以参考此链接以获取有关批量更新和创建的更多信息。 批量更新和创建