最近マリオカート8DXにはまっているmizkyです。
業務でDjangoで使用をしている際に、データベースのレコードを一括で更新する方法について調べていました。
すると、
- update()
- bulk_update()
の2つが存在しており、これらの違いが分からず混乱しました。
そこで、この2つの違いをまとめてみました。
今回の調査で使用するデータベースのレコードは以下の通りです。
mysql> select * from books_book;
+----+-------+---------+
| id | title | author |
+----+-------+---------+
| 1 | 本A | 著者A |
| 2 | 本B | 著者B |
| 3 | 本C | 著者C |
+----+-------+---------+
Djangoのバージョンは3.2.15です。
1. update()について
1.1 基本的な動作
update()は特定のフィールドの値を一括更新します。
例えば全レコードに対してauthorを「自分」にしたい場合は、以下のようにupdate()を使用します。
Book.objects.update(
author = '自分',
)
再度レコードを確認すると、以下のようにauthorが全て「自分」で更新されていることが分かります。
+----+-------+--------+
| id | title | author |
+----+-------+--------+
| 1 | 本A | 自分 |
| 2 | 本B | 自分 |
| 3 | 本C | 自分 |
+----+-------+--------+
1.2 返り値
update()の返り値は更新されたレコード数です。
updated_book_count = Book.objects.filter(
id__in = [2, 3],
).update(
author = '自分',
)
print(updated_book_count)
#結果
2
2. bulk_update()について
2.1 基本的な動作
1.1でupdate()を用いて書いたコードを、bulk_update()を使用して書くと以下のようになります。
books = Book.objects.all()
for book in books:
book.author = '自分'
Book.objects.bulk_update(
books,
['author'],
)
コードの説明です。
1行目で、Bookのレコードを全て取得します。
2, 3行目で取得したBookのレコードに対して、ループ処理を行い、各レコードのauthorを’自分’に代入します。
4行目以降で、Bookの全てのレコードに対して更新を行っています。
bulk_updateの引数は
第1引数に更新対象となるオブジェクト
第2引数にフィールド
を渡します。
もちろん結果は、変わらずauthorが全て「自分」となります。
+----+-------+--------+
| id | title | author |
+----+-------+--------+
| 1 | 本A | 自分 |
| 2 | 本B | 自分 |
| 3 | 本C | 自分 |
+----+-------+--------+
全てのレコードを更新する場合において、update()とbulk_update()を比較してみると、
update()の方がコード量が少なく読みやすいです。
2.2 各レコードのフィールドに対して、異なる値が保存できる
bulk_updateの利点は、各レコードに対して異なる値を一括で更新できる点です。
例えば、
id:1 のレコードのauthorは親戚A、
id: 2のレコードのauthorは知り合いB,
id: 3のレコードには彼女C
を挿入したい場合について考えてみます。
(彼女A, Bなんていないです。)
save()を使用すれば以下のように書くことができます。
book = Book.objects.get(id=1)
book.author = '親戚A'
book.save()
book = Book.objects.get(id=2)
book.author = '知り合いB'
book.save()
book = Book.objects.get(id=3)
book.author = '彼女C'
book.save()
for文を用いれば、もう少し簡潔に書くことができますが
馬鹿正直に書くと、このようなコードとなります。
今度はbulk_update()を使用して書いてみます。
books = []
for book in Book.objects.all():
if book.id == 1:
book.author = '親戚A'
elif book.id == 2:
book.author = '知り合いB'
elif book.id == 3:
book.author = '彼女C'
books.append(book)
Book.objects.bulk_update(books, fields=['author'])
少し読みやすくなりました。
2.3 返り値
bulk_update()の返り値を調べてみました。
books = Book.objects.all()
for book in books:
book.author = 'おっちゃん'
updated_book_count = Book.objects.bulk_update(
books,
['author'],
)
print(updated_book_count)
#結果
None
どうやら更新されたレコード数は返ってこないようです。
一応公式URLを確認したところ、
Changed in Django 4.0:
https://docs.djangoproject.com/en/4.1/ref/models/querysets/#bulk-update
The return value of the number of objects updated was added.
と書いていたので、バージョン4.0からは更新されたレコード数が返ってくる仕様になったようです。
3. まとめ
今回はDjangoのupdate()とbulk_update()について調べました。
update()は
- フィールドの値を同じ値で一括更新する。
- 返り値は更新したレコード数
bulk_update()は
- フィールドの値を異なる値で一括更新する。(同じ値も可)
- 返り値は無し。(バージョン4.0では更新したレコード数となる。)
となるようです。
4. 参考URL
参考にした公式サイトのリンクを掲載します。
update()についてです。

bulk_update()についてです。


「mizky」で「みずき」と読みます。エンターテイナーになりたい。普段はサラリーマン(気持ちは引き篭もりニート)。アプリ開発、HP運営、投資など手広くやっております。九州大学大学院卒業。趣味は旅行、レースゲーム。
コメント