【Django】update()とbulk_update()の違い

eyecatch_django_diff_between_update_and_bulk_update

最近マリオカート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:
The return value of the number of objects updated was added.

https://docs.djangoproject.com/en/4.1/ref/models/querysets/#bulk-update

と書いていたので、バージョン4.0からは更新されたレコード数が返ってくる仕様になったようです。

3. まとめ

今回はDjangoのupdate()とbulk_update()について調べました。

update()は

  • フィールドの値を同じ値で一括更新する。
  • 返り値は更新したレコード数

bulk_update()は

  • フィールドの値を異なる値で一括更新する。(同じ値も可)
  • 返り値は無し。(バージョン4.0では更新したレコード数となる。)

となるようです。

4. 参考URL

参考にした公式サイトのリンクを掲載します。

update()についてです。

Django
The web framework for perfectionists with deadlines.

bulk_update()についてです。

Django
The web framework for perfectionists with deadlines.

コメント

タイトルとURLをコピーしました