djangoでモデルオブジェクトを一括作成する


90

データベースに保存するオブジェクトがたくさんあるので、それを使ってモデルインスタンスを作成したいと思います。

djangoを使用すると、を使用してすべてのモデルインスタンスを作成できますMyModel(data)。次に、それらをすべて保存します。

現在、私はそのようなものを持っています:

for item in items:
    object = MyModel(name=item.name)
    object.save()

オブジェクトのリストを直接保存できるかどうか疑問に思っています。例:

objects = []
for item in items:
    objects.append(MyModel(name=item.name))
objects.save_all()

1つのトランザクションですべてのオブジェクトを保存するにはどうすればよいですか?



1
list.save_allを知りたいですか?疑問に思っている言い換えだけで、トピックの質問の最初の2つの単語を使用することができます。
— SławomirLenart

回答:


95

djangoの開発時点ではbulk_create、クラスコンストラクターを使用して作成されたオブジェクトの配列を入力として受け取るオブジェクトマネージャーメソッドが存在します。djangoドキュメントをチェックしてください



1
ただし、save()が自動的に実行するAutoFieldの場合、bulk_createには主キーが作成されないなど、いくつかの制限があることに注意してください。
— Hitesh Garg 2015

@HiteshGarg、それは今でも本当ですか?
— レイデルミランダ2017

1
@RaydelMiranda、はい、それはまだ本当です。それはドキュメントにあります:If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does, unless the database backend supports it (currently only PostgreSQL).
— interDist 2018

1
使用してDjangoの3.0.xのを、私は使用していることを確認してbulk_create()任意の信号をトリガしません。なんでだろうか。
— エンチャント

42

bulk_create()メソッドを使用します。現在、Djangoでは標準です。

例:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])

1
Django 1.10で変更:PostgreSQLの使用時にbulk_create()を使用して作成されたオブジェクトに主キーを設定するためのサポートが追加されました。
— エラッドシルバー2017

4

ループ(postgres 9.1)に手動のトランザクション処理を使用するように働きました:

from django.db import transaction
with transaction.commit_on_success():
    for item in items:
        MyModel.objects.create(name=item.name)

実際、「ネイティブ」データベースの一括挿入と同じではありませんが、トランスポート/ orms操作/ SQLクエリ分析コストを回避/削減できます。


1
これは少し変わった。これで、トランザクションはcommit_on_successもうありません。あなたは使用する必要がありますtransaction.atomic():参照stackoverflow.com/questions/21861207/...を
— t_io

4

次に、列で区切られたファイルからエンティティを一括作成し、引用符を外したりエスケープしたりしないルーチンをすべて残しておく方法を示します。

SomeModel(Model):
    @classmethod
    def from_file(model, file_obj, headers, delimiter):
        model.objects.bulk_create([
            model(**dict(zip(headers, line.split(delimiter))))
            for line in file_obj],
            batch_size=None)

3

単一行の実装の場合、マップでラムダ式を使用できます

map(lambda x:MyModel.objects.get_or_create(name=x), items)

ここで、ラムダはアイテムリストの各アイテムをxと照合し、必要に応じてデータベースレコードを作成します。

Lambdaドキュメント


あなたはおそらく、lambdaをmap乗り越えなければならないことに言及したいと思うでしょうitems:map(lambda name: MyModel.objects.get_or_create(name = name), items)
— Manoj Govindan 2010

Ja、それは私が言おうとしている別の方法です(:
— FallenAngel 2010

2

createを使用すると、新しいアイテムごとに1つのクエリが発生します。INSERTクエリの数を減らしたい場合は、別のものを使用する必要があります。

スニペットはかなり古いものですが、一括挿入スニペットを使用してある程度の成功を収めています。おそらく、それを再び機能させるために必要ないくつかの変更があります。

http://djangosnippets.org/snippets/446/


2

Bulkopsモジュールに関するこのブログ投稿を確認してください。

私のdjango1.3アプリでは、大幅なスピードアップを経験しました。


-19

最も簡単な方法はcreate、単一のステップでオブジェクトを作成および保存するManagerメソッドを使用することです。

for item in items:
    MyModel.objects.create(name=item.name)

+1。nameが一意であり、入力が重複する可能性がある場合は、を使用することをお勧めしますget_or_create。
— Manoj Govindan 2010

16
これはどのように質問に答えますか?Model.objects.createは、object = MoModel(..)object.save()と同等です。そして、これは1つのトランザクションでは実行されません...
— automagic
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.