Django での一括更新
Django では、デフォルトで、すべてのモデルにオブジェクト
マネージャーがあります。このマネージャーは、モデルインスタンスのフェッチ、モデルインスタンスのフィルター処理、モデルインスタンスの削除などの多くのことを実行できます。Django が提供するベースマネージャーを継承することで、独自のマネージャーを作成することもできます。
これで、get()
関数を使用して単一のモデルインスタンスを取得したり、filter()
メソッドを使用してインスタンスをフィルタリングしたりするなど、適用するすべてのクエリがデータベースに 1 回ヒットします。これは、次のように 5つの get()
ステートメントがある場合、データベースは個別に 5 回クエリされることを意味します。
person = Person.objects.get(id=1)
person = Person.objects.get(id=2)
person = Person.objects.get(id=3)
person = Person.objects.get(id=4)
person = Person.objects.get(id=5)
これは、単一のタスクに対して個別にデータベースにアクセスするため、非効率的なアプローチです。一部のモデルで多くのインスタンスをクエリしたり、多くのインスタンスを更新したりする必要がある場合、このアプローチによりアプリケーションの速度が大幅に低下する可能性があります。
この問題を解決するために、Django には、通常、1つのクエリで複数のインスタンスを更新するために使用できる関数が組み込まれています。
Django の bulk_update()
メソッド
bulk_update
メソッドには、objs
、fields
、および batch_size
の 3つのパラメーターがあります。
objs
- 実行する操作のリストfields
- クエリを実行する必要があるフィールドのリストbatch_size
- 1つのデータベースクエリに保存されるオブジェクトの数。これはオプションの引数です。デフォルトでは、すべてのオブジェクトが更新および保存されます。
例を考えてみましょう。Person
モデルがあり、bulk_update()
メソッドを使用してすべての人の年齢を 1
インクリメントする必要があるとします。次のようにします。
models.py
:
from django.db import models
class Person(models.Model):
username = models.CharField(max_length=200, unique=True)
firstName = models.CharField(max_length=200)
middleName = models.CharField(max_length=200)
lastName = models.CharField(max_length=200)
age = models.IntegerField(default=0)
views.py
:
people = Person.objects.all()
for person in people:
person.age += 1
Person.objects.bulk_update(people, update_fields=["age"])
この操作により、1 回のクエリですべての人の年齢が更新されます。これは非常に効率的です。
bulk_update()
メソッドの欠点
bulk_update()
メソッドは優れていますが、輝くものすべてが金であるわけではありません。この方法にはいくつかの欠点があります。
bulk_update()
メソッドを使用すると、インスタンスの主キーを更新できません。- すべてのモデルには
save()
メソッドがあります。bulk_update()
メソッドを使用する場合、このメソッドは呼び出されません。 - 多くのレコードの多くの列を更新する場合は、バッチサイズについて言及する必要があります。そうしないと、生成される SQL クエリが非常に長くなります。