Есть ли способ получить первичные ключи созданных вами элементов с помощью функции bulk_create в django 1.4 +?
Как получить первичные ключи объектов, созданных с помощью django bulk_create
Ответ 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>]