queryset - Cómo obtener las claves principales de los objetos creados con django bulk_create
objects.filter django (8)
¿Hay alguna manera de obtener las claves principales de los elementos que ha creado utilizando la función bulk_create en django 1.4+?
2016
Django 1.10: ahora es compatible (¡solo en Postgres!) Aquí hay un enlace al documento .
>>> 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
Del registro de cambios:
Modificado en Django 1.10: Se agregó compatibilidad con la configuración de claves primarias en objetos creados con bulk_create () al usar PostgreSQL
Dos enfoques que puedo pensar:
a) Podrías hacer
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)
Esto podría ser un poco caro si el conjunto de consulta es extremadamente grande.
b) Si el modelo tiene un campo 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)
Esto tiene la limitación de tener un campo que almacena cuando se creó el objeto.
En realidad, mi colega me ha sugerido la siguiente solución que ahora parece tan obvia. Agregue una nueva columna llamada bulk_ref
que bulk_ref
con un valor único e inserte para cada fila. Luego simplemente consulta la tabla con el bulk_ref
establecido de antemano y listo, tus registros insertados son recuperados. p.ej:
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)
Esto debería funcionar.
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>]
Esto no funciona en stock Django, pero hay un code.djangoproject.com/ticket/19527 que hace que bulk_create establezca las claves principales para los objetos creados.
La documentación de django actualmente establece bajo las limitaciones:
Si la clave principal del modelo es un AutoField, no recupera ni establece el atributo de la clave principal, como lo hace
save()
.
Pero hay buenas noticias. Ha habido un par de tickets hablando de bulk_create
desde la memoria. El code.djangoproject.com/ticket/19527 es el más probable para tener una solución que pronto será implementada pero obviamente no hay garantía a tiempo o si alguna vez lo hará.
Entonces hay dos soluciones posibles,
Espere y vea si este parche llega a la producción. Puede ayudar con esto probando la solución indicada y dejar que la comunidad django conozca sus pensamientos / problemas. https://code.djangoproject.com/attachment/ticket/19527/bulk_create_and_create_schema_django_v1.5.1.patch
Anula / escribe tu propia solución de inserción masiva.
Probablemente la solución más simple es la asignación manual de claves principales. Depende de un caso particular, pero a veces es suficiente comenzar con max (id) +1 desde la tabla y asignar números incrementando en cada objeto. Sin embargo, si varios clientes pueden insertar registros simultáneamente, puede ser necesario un bloqueo.
Según la documentación, no puede hacerlo: docs.djangoproject.com/en/dev/ref/models/querysets/#bulk-create
bulk-create es solo para eso: crea una gran cantidad de objetos de manera eficiente, ahorrando muchas consultas. Pero eso significa que la respuesta que obtienes es incompleta. Si lo haces:
>>> 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]
Eso no significa que sus categorías no tengan pk, solo que la consulta no los recuperó (si la clave es un AutoField
). Si desea los pks por algún motivo, deberá guardar los objetos de forma clásica.