7

Python 2.7.9 Django 1.7 MySQL 5.6Django - efficiente bulk creare modelli ereditati

vorrei popolare un intero gruppo di istanze di oggetti appartenenti a più classi, li impilare in un unico create() -come interrogazione , aprire una connessione al database, eseguire la query, quindi chiudere. La mia motivazione principale è la performance, ma la compattezza del codice è anche un vantaggio.

La funzionalità di bulk_create() sembra essere esattamente quello che voglio, ma sono in violazione di almeno uno dei caveat elencati here, cioè

It does not work with many-to-many relationships.

e

It does not work with child models in a multi-table inheritance scenario.

Queste limitazioni sono anche descritto in the source code:

# So this case is fun. When you bulk insert you don't get the primary 
# keys back (if it's an autoincrement), so you can't insert into the 
# child tables which references this. There are two workarounds, 1) 
# this could be implemented if you didn't have an autoincrement pk, 
# and 2) you could do it by doing O(n) normal inserts into the parent 
# tables to get the primary keys back, and then doing a single bulk 
# insert into the childmost table. Some databases might allow doing 
# this by using RETURNING clause for the insert query. We're punting 
# on these for now because they are relatively rare cases. 

Ma l'errore restituito quando tento è il generico

ValueError: Can't bulk create an inherited model

I miei modelli non apparentemente contengono molti-a-molti campi o chiavi esterne. Non mi è del tutto chiaro quali siano gli scenari di ereditarietà multi-tavolo a cui si riferiscono, quindi non sono sicuro che questo sia il mio problema. Speravo che potrei scivolare vicino con la mia struttura che assomiglia a questo, ma poi ho avuto l'errore generale, quindi niente da fare:

child class with OneToOneField---\ 
            \ 
child class with OneToOneField----->---concrete parent class 
           /
child class with OneToOneField---/ 

Per quanto riguarda le soluzioni alternative suggerite nella fonte, # 1 non è un'opzione per io, e il n. 2 non sono allettanti perché presumo che comporterebbe il sacrificio dei guadagni in termini di prestazioni che sto cercando.

Esistono altri metodi per simulare lo bulk_create() durante la gestione dell'eredità come questa e non rinunciare ai guadagni in termini di prestazioni? Devo tornare indietro a SQL raw? Non mi dispiacerebbe fare una raccolta separata e l'esecuzione di un separato INSERT/create() per ogni tipo di oggetto figlio.

risposta

8

La soluzione su cui mi sono accontentato era il confezionamento di tutti i miei articoli raccolti create() in un with transaction.atomic():. Questo ha ridotto notevolmente il tempo di esecuzione non aprendo alcuna connessione al database o eseguendo alcuna query fino a quando tutto il Python non fosse tornato.

Uno svantaggio potrebbe essere che se si verificano degli errori, tutte le modifiche vengono ripristinate e il database non viene toccato. Questo potrebbe essere risolto tagliando i lotti create() in lotti e aprendo e chiudendo una transazione intorno a ciascuno di essi. (Nel mio caso questo non era il comportamento desiderato perché volevo tutti i dati o nessuno di essi.)