Creación masiva de objetos modelo en django

90

Tengo muchos objetos para guardar en la base de datos, por lo que quiero crear instancias de modelo con eso.

Con django, puedo crear todas las instancias de modelos, con MyModel(data), y luego quiero guardarlas todas.

Actualmente, tengo algo así:

for item in items:
    object = MyModel(name=item.name)
    object.save()

Me pregunto si puedo guardar una lista de objetos directamente, por ejemplo:

objects = []
for item in items:
    objects.append(MyModel(name=item.name))
objects.save_all()

¿Cómo guardar todos los objetos en una transacción?

Alexis Métaireau
fuente
Parece que la bola está rodando en la implementación de una solución para este código
Djangoproject.com/ticket/19527
1
preguntando por list.save_all? Casi podría responderse a sí mismo, simplemente parafrasear esa pregunta y usar 2 primeras palabras de su pregunta temática.
Sławomir Lenart

Respuestas:

95

A partir del desarrollo de django, existe bulk_createun método de administrador de objetos que toma como entrada una matriz de objetos creados usando el constructor de clases. echa un vistazo a los documentos de django

ecbtln
fuente
1
Pero recuerde que bulk_create tiene algunas limitaciones, como que no crea claves primarias si es un AutoField que save () lo hace automáticamente.
Hitesh Garg
@HiteshGarg, ¿eso sigue siendo cierto hoy en día?
Raydel Miranda
1
@RaydelMiranda, sí, todavía es cierto. Está ahí mismo en la documentación:If the model’s primary key is an AutoField it does not retrieve and set the primary key attribute, as save() does, unless the database backend supports it (currently only PostgreSQL).
interDist
1
Usando Django 3.0.xy confirmo que el uso bulk_create()no activa ninguna señal. Me pregunto porque.
mejora el
42

bulk_create()Método de uso . Ahora es estándar en Django.

Ejemplo:

Entry.objects.bulk_create([
    Entry(headline="Django 1.0 Released"),
    Entry(headline="Django 1.1 Announced"),
    Entry(headline="Breaking: Django is awesome")
])
Danil
fuente
1
Cambiado en Django 1.10: Se agregó soporte para configurar claves primarias en objetos creados usando bulk_create () cuando se usa PostgreSQL.
elad silver
4

Me funcionó para usar el manejo manual de transacciones para el bucle (postgres 9.1):

from django.db import transaction
with transaction.commit_on_success():
    for item in items:
        MyModel.objects.create(name=item.name)

de hecho, no es lo mismo que la inserción masiva de la base de datos 'nativa', pero le permite evitar / disminuir el transporte / operaciones de orms / costos de análisis de consultas SQL

eviltnan
fuente
1
Esto cambió ligeramente. Ahora la transacción ya no tiene commit_on_success. Debe usar transaction.atomic()Ver: stackoverflow.com/questions/21861207/…
t_io
4

A continuación, se explica cómo crear entidades de forma masiva a partir de archivos separados por columnas, dejando de lado todas las rutinas sin comillas y sin escape:

SomeModel(Model):
    @classmethod
    def from_file(model, file_obj, headers, delimiter):
        model.objects.bulk_create([
            model(**dict(zip(headers, line.split(delimiter))))
            for line in file_obj],
            batch_size=None)
Ivan Klass
fuente
3

para una implementación de una sola línea, puede usar una expresión lambda en un mapa

map(lambda x:MyModel.objects.get_or_create(name=x), items)

Aquí, lambda hace coincidir cada elemento en la lista de elementos ax y crea un registro de base de datos si es necesario.

Documentación de Lambda

Ángel caido
fuente
Probablemente quiera mencionar que lambdatiene que mappasar items:map(lambda name: MyModel.objects.get_or_create(name = name), items)
Manoj Govindan
Ja,
esa
2

El uso de crear generará una consulta por cada elemento nuevo. Si desea reducir la cantidad de consultas INSERT, deberá usar algo más.

He tenido cierto éxito con el fragmento de inserción masiva, aunque el fragmento es bastante antiguo. Quizás se requieran algunos cambios para que vuelva a funcionar.

http://djangosnippets.org/snippets/446/

OmerGertel
fuente
2

Consulte esta publicación de blog sobre el módulo bulkops .

En mi aplicación django 1.3, he experimentado una aceleración significativa.

MrJ
fuente
-19

La forma más sencilla es utilizar el createmétodo Manager, que crea y guarda el objeto en un solo paso.

for item in items:
    MyModel.objects.create(name=item.name)
Daniel Roseman
fuente
+1. Siname es único y son posibles entradas duplicadas, sería una buena idea utilizarlo get_or_create.
Manoj Govindan
16
¿Cómo responde esto a la pregunta? Model.objects.create es equivalente a object = MoModel (..) object.save (). Y esto no lo hace en una sola transacción ...
automagic