2009-10-26 27 views
5

Sto cercando di costruire automaticamente una copia di un SA-mapped oggetto .. Al momento la mia funzione è solo:SQLAlchemy: copia superficiale evitando lazy loading

newobj = src.__class__() 
for prop in class_mapper(src.__class__).iterate_properties: 
    setattr(newobj, prop.key, getattr(src, prop.key)) 

ma sto avendo problemi con le relazioni pigre ... Ovviamente getattr attiva il caricamento lazy, ma poiché non ho bisogno dei loro valori a destra dello , mi piacerebbe solo copiare il "questo dovrebbe essere pigro carico" -stato di l'attributo .. . È possibile?

Modifica: Ho bisogno di questo per un sistema di "registrazione dati". Cioè, ogni volta che qualcuno aggiorna un'entità persistente, devo generare un nuovo record e quindi contrassegnare quello vecchio come tale.
Per fare questo, creo una copia superficiale dell'entità (quindi SQLA emette un INSERT invece di un UPDATE) e lavora da lì .. Il sistema funziona in modo abbastanza piacevole (è stato utilizzato in produzione per mesi) ma ora I 'Mi piacerebbe migliorarlo in modo che non abbia bisogno che tutte le relazioni vengano caricate prima.

+0

È la registrazione di modifica? Sembra più simile al sistema di controllo delle versioni mantenendo la cronologia di tutti gli stati storici. –

+0

Esattamente, mantiene ogni versione dell'entità – Joril

+1

invece di 'class_mapper (src .__ class __)', esegue 'object_mapper (src)'. Evita di accedere direttamente agli attributi '__foo__'. – nosklo

risposta

6

Quello che ti serve è copiare solo le proprietà delle colonne, che possono essere facilmente filtrate usando isinstance(prop, sqlalchemy.orm.ColumnProperty). Nota che devi copiare le relazioni memorizzate esternamente (tutte many-to-many), poiché non ci sono colonne corrispondenti a loro nella tabella principale. Questo non può essere fatto con l'interfaccia di alto livello senza caricamento lento, quindi preferirei accettare questo compromesso. Le relazioni molti-a-molti possono essere determinate con il test isinstance(prop, RelationProperty) and prop.secondary. Il codice risultante sarà simile alla seguente:

from sqlalchemy.orm import object_mapper, ColumnProperty, RelationProperty 

newobj = type(src)() 
for prop in object_mapper(src).iterate_properties: 
    if (isinstance(prop, ColumnProperty) or 
     isinstance(prop, RelationProperty) and prop.secondary): 
    setattr(newobj, prop.key, getattr(src, prop.key)) 

Si noti inoltre, che SQLAlchemy è progettato per mantenere singolo oggetto caricato per ciascuna identità, mentre la vostra copia rompe questo quando l'identità (chiave primaria) proprietà vengono copiati troppo, ma questo probabilmente non è il tuo caso se stai memorizzando con un nuovo identificativo (versione).

+0

Ok modifica la domanda .. :) – Joril