select_related queryset objects example cual consultas avanzadas django django-models django-views django-queryset

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>]



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,

  1. 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

  2. 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.