web-dev-qa-db-ja.com

Django bulk_createを使用して作成されたオブジェクトの主キーを取得する方法

Django 1.4+のbulk_create機能を使用して作成したアイテムの主キーを取得する方法はありますか?

62
mikec

2016年

Django 1.10-)がサポートされた(Postgresのみ) ドキュメントへのリンク

>>> list_of_objects = Entry.objects.bulk_create([
...     Entry(headline="Django 2.0 Released"),
...     Entry(headline="Django 2.1 Announced"),
...     Entry(headline="Breaking: Django is awesome")
... ])
>>> list_of_objects[0].id
1

変更ログから:

変更されたDjango 1.10:PostgreSQLの使用時にbulk_create()を使用して作成されたオブジェクトに主キーを設定するサポートが追加されました

51
Or Duan

ドキュメントによると、あなたはそれを行うことができません: https://docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create

bulk-createはそのためだけのものです。多くのクエリを保存する効率的な方法で多くのオブジェクトを作成します。しかし、それはあなたが得る応答が一種の不完全であることを意味します。もしあなたがそうするなら:

>>> categories = Category.objects.bulk_create([
    Category(titel="Python", user=user),
    Category(titel="Django", user=user),
    Category(titel="HTML5", user=user),
])

>>> [x.pk for x in categories]
[None, None, None]

これは、カテゴリにpkがないことを意味するのではなく、クエリがそれらを取得しなかったことだけを意味します(キーがAutoFieldの場合)。何らかの理由でpksが必要な場合は、古典的な方法でオブジェクトを保存する必要があります。

28
pyriku

私が考えることができる2つのアプローチ:

a)できること

category_ids = Category.objects.values_list('id', flat=True)
categories = Category.objects.bulk_create([
    Category(title="title1", user=user, created_at=now),
    Category(title="title2", user=user, created_at=now),
    Category(title="title3", user=user, created_at=now),
])
new_categories_ids = Category.objects.exclude(id__in=category_ids).values_list('id', flat=True)

クエリセットが非常に大きい場合、これは少し高価になる可能性があります。

b)モデルにcreated_atフィールドがある場合、

now = datetime.datetime.now()
categories = Category.objects.bulk_create([
    Category(title="title1", user=user, created_at=now),
    Category(title="title2", user=user, created_at=now),
    Category(title="title3", user=user, created_at=now),
])

new_cats = Category.objects.filter(created_at >= now).values_list('id', flat=True)

これには、オブジェクトが作成されたときに保存するフィールドを持つという制限があります。

23
karthikr

実際、私の同僚は次の解決策を提案しましたが、それは今ではとても明白です。 bulk_refという新しい列を追加します。この列には一意の値を入力し、すべての行に挿入します。その後、事前にbulk_refを設定してテーブルにクエリを実行するだけで、挿入されたレコードが取得されます。例えば。:

cars = [Car(
    model="Ford",
    color="Blue",
    price="5000",
    bulk_ref=5,
),Car(
    model="Honda",
    color="Silver",
    price="6000",
    bulk_ref=5,
)]
Car.objects.bulk_create(cars)
qs = Car.objects.filter(bulk_ref=5)
11
DanH

おそらく最も簡単な回避策は、主キーを手動で割り当てることです。特定のケースに依存しますが、テーブルからmax(id)+1で開始し、すべてのオブジェクトに増分する番号を割り当てるだけで十分な場合があります。ただし、複数のクライアントが同時にレコードを挿入する場合、何らかのロックが必要になる場合があります。

0
peper0

これは標準のDjangoでは機能しませんが、 Djangoバグトラッカー)のパッチ があり、bulk_createが作成されたオブジェクトの主キーを設定します。

0
user3175220

Django documentation は現在、制限の下で述べています:

モデルの主キーがAutoFieldである場合、save()のように主キー属性を取得および設定しません。

しかし、良いニュースがあります。メモリからbulk_createについて話すチケットがいくつかありました。 上記のチケット は、すぐに実装されるソリューションを持っている可能性が最も高いですが、明らかに、時間に関する保証はありません。

したがって、2つの解決策があります。

  1. このパッチが実稼働するかどうかを確認してください。上記の解決策をテストして、Djangoコミュニティにあなたの考えや問題を知らせてください。 https://code.djangoproject.com/attachment/ticket/19527 /bulk_create_and_create_schema_Django_v1.5.1.patch

  2. 独自の一括挿入ソリューションをオーバーライド/作成します。

0
Matt Seymour