Djangoでオブジェクトを一括作成・更新【bulk_create, bulk_update】
目次
- Djangoのbulk_createでオブジェクトを一括作成
- create()を使ったオブジェクトの作成
- bulk_create()を使ったオブジェクトの作成
- bulk_update()を使ったオブジェクトの更新
- おわりに
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を動かす時の設定
DjangoのQオブジェクトの使い方: OR検索、否定
DjangoのDateTimeFieldの詳しい使い方: 日付と時刻を扱うフィールド
Djangoのrunserverがつながらない?原因はWebpackでした
DjangoのFormの初期値の設定方法: initial属性の使い方
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()で大量挿入!
関連記事
- Pythonのリストにデータを追加(append)する方法【extend, insert, スライス】
- Pythonでbytes型をstr型に(byte to string)変換する
- Pythonのリストのappend()の使い方【初心者向け完全解説】
- Pythonで複数のフォルダを作成する方法【os.mkdir, os.makedirs】
- Pythonの可変長引数(*args, **kwargs)にリスト、タプル、辞書を展開して渡す
- Pythonでべき乗する方法(**演算子とpow関数)
- Pythonのstr.split()で最初だけ分割する
- PythonのGUIライブラリTkinterでウィンドウを作る方法