如何使用Django“批量更新”?

bvn4nwqk  于 2023-03-20  发布在  Go
关注(0)|答案(8)|浏览(210)

我想用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()

有没有更优雅的方式?

pjngdqdw

pjngdqdw1#

这里是一个有用的内容,我发现在互联网上关于上述问题
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

使用批量更新

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")

有任何向上的投票吗?提前感谢:谢谢你的关注)

yuvru6vn

yuvru6vn2#

要使用相同的值进行更新,只需使用以下命令

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)

它不会每次触发保存信号,而是我们将所有要更新的对象保留在列表中,并立即触发更新信号。

00jrzges

00jrzges3#

IT返回表中更新的对象数。

update_counts = ModelClass.objects.filter(name='bar').update(name="foo")

您可以参考此链接以获取有关批量更新和创建的详细信息。Bulk update and Create

fkvaft9z

fkvaft9z4#

在Django4.1QuerySet.bulk_create()中,可以使用更新字段。当行插入不满足唯一性约束时,执行更新。
bulk_create()现在支持在行插入不满足唯一性约束时更新字段。MariaDB、MySQL、PostgreSQL和SQLite 3.24+支持此功能。

2skhul33

2skhul335#

更新:

Django2.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)

请参见documentation
但是,请注意:

  • 这不会使用ModelClass.save方法(因此,如果您在其中有一些逻辑,它将不会被触发)。
  • 不会发出任何django信号。
  • 您不能在切片的QuerySet上执行.update(),它必须在原始QuerySet上执行,因此您需要依靠.filter().exclude()方法。
h7wcgrx3

h7wcgrx36#

考虑使用django-bulk-update找到here on GitHub
安装: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和查询复杂性。这个工具更像是一辆手巴罗,而不是自卸卡车。

c9x0cxw0

c9x0cxw07#

Django2.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])
u3r8eeie

u3r8eeie8#

如果要在行集合上设置相同的值,可以将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/Event sourcing。

相关问题