2010-02-12 8 views

Respuesta

8

No puede hacer inserciones masivas decentes con get_or_create (o incluso crear), y no hay API para hacer esto fácilmente.

Si su tabla es lo suficientemente simple como para crear filas con SQL sin formato no es demasiado doloroso, no es demasiado difícil; algo así como:

INSERT INTO site_entry (field1, field2) 
(
     SELECT i.field1, i.field2 
     FROM (VALUES %s) AS i(field1, field2) 
     LEFT JOIN site_entry as existing 
       ON (existing.field1 = i.field1 AND existing.field2 = i.field2) 
     WHERE existing.id IS NULL 
) 

donde% s es una cadena como ("field1, field2"), ("field3, field4"), ("field5, field6") que usted tiene que crear y escapar adecuadamente a sí mismo.

+0

De la forma en que lo hice, puedes insertar muchos cientos de filas en una sola consulta, que es lo que generalmente quieres hacer inserciones por lotes. –

+0

Sí, pero no puedo hacerlo con MySQL. Parece que no puedo encontrar la sintaxis SQL correcta con su consulta propuesta. – kemar

+0

¿Qué le parece obtener? ¿Cómo va a recibir un objeto modelo, en caso de ejecución? esta consulta? –

4

Depende de lo que usted está apuntando. Puede usar la función manage.pyloaddata para cargar datos en un formato apropiado (JSON, XML, YAML, ...).

Véase también this discussion.

+2

que es un enlace roto ahora – wim

0

Yo diría que no lo es.

Pero me pregunto qué tipo son sus item s, si tienen field1 y field2 como atributos. Parece que existe otra clase que representa una entrada pero no deriva de models.Model. Tal vez pueda omitir esta clase y crear instancias Entry inmediatamente en lugar de crear esos elementos.

1

Si no está seguro de si las cosas en su item_list ya existen en su base de datos y necesita los objetos modelo, entonces get_or_create es definitivamente el camino a seguir.

Si conoce los artículos no se encuentran en su base de datos, que sería mucho mejor haciendo:

for item in item_list: 
    new = Entry.objects.create(
     field1 = item.field1, 
     field2 = item.field2, 
    ) 

Y si usted no necesita los objetos, entonces simplemente ignorar el regreso de la llamada a la función. No acelerará las cosas de DB, pero ayudará con la administración de la memoria si eso es un problema.

Si no está seguro de si los datos ya están en la base de datos, pero cualquiera de los campos tiene una bandera unique=True, entonces la base de datos hará valer la exclusividad y podrá capturar la excepción y continuar. Esto evitará un DB extra al evitar el intento de seleccionar el objeto existente.

from django.db import IntegrityError 

for item in item_list: 
    try: 
     new = Entry.objects.create(
      field1 = item.field1, 
      field2 = item.field2, 
     ) 
    except IntegrityError: 
     continue 

Puede aumentar la velocidad en cualquier caso administrando manualmente las transacciones. Django creará y realizará automáticamente una transacción para cada operación de guardado, pero ofrece algunos decoradores que aumentarán en gran medida la eficiencia si sabe que hará una gran cantidad de copias de seguridad en una función en particular. Los documentos de Django hacen un mejor trabajo al explicar todo esto que aquí, pero es probable que desee prestar especial atención a django.db.transaction.commit_on_success

+1

elementos en mi lista_de_objetos * pueden * ya existir en mi base de datos, y sí, necesito los objetos modelo. Y ninguno de los campos tiene una restricción unique = True: '(Así que creo que get_or_create es el camino a seguir. ¡Vamos a la base de datos! – kemar

+4

Esto no responde a la pregunta. Primero, dijo que quería * bulk * insert; "get_or_create es el camino a seguir" no ayuda, ya que get_or_create no hace inserciones masivas. Insertar ítems uno a la vez es lo incorrecto para la inserción masiva. Finalmente, no puedes simplemente causar errores y luego ignorar En Postgresql terminarás con errores de "transacción abortada" a menos que saltes en el punto de control. –

1

Desde 1.4 se puede hacer bulk_create

Ver the docs

* No prestar atención a las advertencias de que (uno más importante es que el método del modelo, salvo() no se llamará, por lo que la pre_save y las señales de post_save no se enviarán.) *

Cuestiones relacionadas