Подтвердить что ты не робот

Как получить первичные ключи объектов, созданных с помощью django bulk_create

Есть ли способ получить первичные ключи созданных вами элементов с помощью функции bulk_create в django 1.4 +?

4b9b3361

Ответ 1

2016

Django 1.10 - теперь поддерживается (только для Postgres!) здесь ссылка на документ.

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

Из журнала изменений:

Изменено в Django 1.10: Добавлена ​​поддержка установки первичных ключей для объектов, созданных с помощью функции bulk_create() при использовании PostgreSQL.

Ответ 2

В соответствии с документацией вы не можете этого сделать: 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 по какой-то причине, вам нужно будет сохранить объекты классическим способом.

Ответ 3

Два подхода, о которых я могу думать:

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)

У этого есть ограничение наличия поля, которое хранится, когда объект был создан.

Ответ 4

На самом деле мой коллега предложил следующее решение, которое кажется таким очевидным сейчас. Добавьте новый столбец с именем bulk_ref, который вы заполняете уникальным значением и вставляете для каждой строки. После этого просто запросите таблицу с параметром bulk_ref заранее, а voila, ваши вставленные записи будут восстановлены. например:.

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)

Ответ 5

Вероятно, самым простым обходным путем является назначение первичных ключей вручную. Это зависит от конкретного случая, но иногда достаточно, чтобы начать с max (id) +1 из таблицы и присваивать числа, увеличивающиеся на каждом объекте. Однако, если несколько клиентов могут вставлять записи одновременно, может потребоваться некоторая блокировка.

Ответ 6

документация django в настоящее время заявляет с ограничениями:

Если первичный ключ модели - это AutoField, он не извлекает и установите атрибут первичного ключа, как это делает save().

Но есть хорошие новости. Несколько билетов говорили о bulk_create из памяти. Билет указанный выше, скорее всего, будет иметь решение, которое скоро будет реализовано, но очевидно, что вовремя нет гарантии или если она когда-либо будет он.

Итак, возможны два возможных решения:

  • Подождите и посмотрите, делает ли этот патч его производство. Вы можете помочь в этом, протестировав заявленное решение, и пусть сообщество django знает ваши мысли/проблемы. https://code.djangoproject.com/attachment/ticket/19527/bulk_create_and_create_schema_django_v1.5.1.patch

  • Переопределить/написать собственное решение для массовой вставки.

Ответ 7

Это не работает на складе Django, но есть патч в отладчике ошибок Django, который делает bulk_create установленными первичными ключами для созданных объекты.

Ответ 8

Это должно работать.

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


>>> categories[0]
[<Category: Python>]
>>> categories[1]
[<Category: Django>]