Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
- 作成日: 2021-06-08
- 更新日: 2023-12-24
- カテゴリ: Python
Djangoのbulk_createでオブジェクトを一括作成
Djangoではモデルを通してオブジェクトをデータベースに作成することができます。
この用途によく使われるのがModel.objects.create()
です。
しかし大量のモデルを作成しようとするとModel.objects.create()
はパフォーマンスを発揮してくれません。
こういう時に使うのがModel.objects.bulk_create()
です。
bulk_create()
を使うと大量のモデルを一括でデータベースに挿入することができます。
普通のcreate()
に比べて非常に高速です。
結論から言うとbulk_create()
でオブジェクトを一括作成するには↓のようなコードを書きます。
from core.models import Article
objs = []
for i in range(10000):
obj = Article(title=f'{i} article')
objs.append(obj)
Article.objects.bulk_create(objs)
この記事ではbulk_create()
とbulk_update()
の詳細について詳しく解説します。
具体的には↓を見ていきます。
- create()を使ったオブジェクトの作成
- bulk_create()を使ったオブジェクトの作成
- bulk_update()を使ったオブジェクトの更新
関連記事
低スペックサーバーでDjangoとuWSGIを動かす時の設定
adminサイトにモデルを追加する【Django】
Django入門: 簡単な一行掲示板アプリを作る その1【Windows10】
Django入門: 管理サイト ~ 簡単な一行掲示板アプリを作る その11【Windows10】
Django入門: 微調整 ~ 簡単な一行掲示板アプリを作る その15【Windows10】
create()を使ったオブジェクトの作成
最初に従来の方法を見てみます。
bulk_create()
を使わない場合はModel.objects.create()
などでオブジェクトを作成するのが普通でした。
↓のようなコードです。
from core.models import Article
for i in range(10000):
Article.objects.create(title=f'{i} article')
↑のコードは実行してみると非常に遅いのがわかります。
10000
件のオブジェクトをデータベースに挿入するわけですが、クエリをcreate()
の呼び出しごとに発行しているので、非常に効率が悪いです。
筆者の環境では数分待っても処理が終わりませんでした。
クエリを分割して実行するのではなく、1つのクエリにまとめれば早くなりそうです。
これを実現するのがbulk_create()
です。
bulk_create()を使ったオブジェクトの作成
bulk_create()
は↓のような構造を持っています。
bulk_create(objs, batch_size=None, ignore_conflicts=False)
第1引数のobjs
にはオブジェクトのリストを渡します。
第2引数にはbatch_size
で、一度のクエリで作成するオブジェクトの数を指定します。デフォルトでは(SQLiteとOracleを除き)すべてのオブジェクトを一回のクエリで作成します。
第3引数のignore_conflicts
をTrue
にすると、bulk_create()
は一意なキーに由来するエラーなどを無視するようになります。
bulk_create()
は↓のように使います。
from core.models import Article
objs = []
for i in range(10000):
obj = Article(title=f'{i} article')
objs.append(obj)
Article.objects.bulk_create(objs)
最初にリストにオブジェクトを1万個保存しておいて、そのリストを↑のようにbulk_create()
に渡します。
こうするとbulk_create()
がリスト(objs
)を使って1つのクエリにまとめて発行してくれます。
こちらのコードは数秒で処理が終わりました。
先ほどのcreate()
のコードが5
分ぐらいだとすると最低でも60
倍は早いということになります。
batch_size
の挙動は↓のコードで確かめられます。
from core.models import Article
objs = []
for i in range(10):
obj = Article(title=f'{i} article')
objs.append(obj)
articles = Article.objects.bulk_create(objs, batch_size=2)
print(articles)
↑のコードを実行すると↓のような結果になります。
[<Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>, <Article: Article object (None)>]
batch_size
を小さくしても最終的に作成されるオブジェクトのサイズは変わりません。
↓はSqlite3でデータベースを見た場合です。
sqlite> select * from core_article;
1|0 article|
2|1 article|
3|2 article|
4|3 article|
5|4 article|
6|5 article|
7|6 article|
8|7 article|
9|8 article|
10|9 article|
bulk_update()を使ったオブジェクトの更新
bulk_update()
は↓のような構造になっています。
bulk_update(objs, fields, batch_size=None)
第1引数には更新させたいオブジェクトのリストを渡します。
第2引数には更新させたいフィール名をリストと文字列で指定します。
第3引数のbatch_size
は一度のクエリで作成するオブジェクトの数を制限します。デフォルトでは(SQLiteとOracleを除き)すべてのオブジェクトを一回で更新します。
bulk_update
は↓のように使います。
from core.models import Article
objs = [
Article.objects.create(title='article 1'),
Article.objects.create(title='article 2'),
]
objs[0].title = '記事 1'
objs[1].title = '記事 2'
Article.objects.bulk_update(objs, ['title'])
↑の場合、最初にobjs
に2つオブジェクトを保存しています。それぞれtitle
フィールドがarticle 1
とarticle 2
になっています。
その後にobjs[0].title = '記事 1'
のようにタイトルを日本語に変更します。
この状態のオブジェクトはまだデータベースに保存されていませんが、bulk_update()
を使うと一括して更新できます。
bulk_update()
の第1引数にオブジェクトのリストを渡し、第2引数に更新させたいフィールドを指定します。
結果的にデータベース(SQLite)の中身は↓のようになります。
sqlite> select * from core_article;
1|記事 1|
2|記事 2|
おわりに
今回はDjangoのbulk_create()
とbulk_update()
について見てみました。
大量のオブジェクトを作成・更新したいときはこれらのメソッドを使うと吉ですね。
🦝 < bulkは「大部分」とか「大半」って意味だよ
🐭 < bulk_create()で大量挿入!