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()
もっとエレガントな方法はありますか?
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)
ドキュメントを参照してください。
ただし、次の点に注意してください。
ModelClass.saveメソッドを使用しません(したがって、内部にロジックがある場合はトリガーされません)。.update()。元のQuerySetに対して実行する必要があるため、.filter()および.exclude()メソッドに依存する必要があります。ここ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
更新:マークがコメントで指摘しているように、これは一度に数千行を更新するのには適していません。それは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])
行のコレクションに同じ値を設定する場合は、update()メソッドを任意のクエリ用語と組み合わせて使用して、1つのクエリのすべての行を更新できます。
some_list = ModelClass.objects.filter(some condition).values('id')
ModelClass.objects.filter(pk__in=some_list).update(foo=bar)
条件に応じて異なる値で行のコレクションを更新する場合は、最良の場合、値に従って更新をバッチ処理できます。列をX値の1つに設定する1000行があるとすると、事前にバッチを準備してから、X個の更新クエリ(それぞれが基本的に上記の最初の例の形式を持つ)+最初のSELECTのみを実行できます。 -クエリ。
すべての行に一意の値が必要な場合、更新ごとに1つのクエリを回避する方法はありません。後者の場合にパフォーマンスが必要な場合は、おそらく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")
一括更新と作成の詳細については、このリンクを参照してください。 一括更新と作成