2012-12-03 9 views
6

Attualmente ho una colonna che contiene markup HTML. Dentro quel markup, c'è un timestamp che voglio memorizzare in una nuova colonna (quindi posso interrogarlo contro di esso). La mia idea era quella di effettuare le seguenti operazioni in una singola migrazione:Utilizzo di SQLAlchemy ORM all'interno di una migrazione di Alembic: come faccio?

  1. Creare un nuovo, colonna Null per i dati
  2. l'ORM di tirare indietro il codice HTML che ho bisogno di analizzare
  3. Per ogni riga
    1. analizzare il HTML per estrarre il timestamp
    2. aggiornamento dell'oggetto ORM

Ma quando provo a eseguire la mia migrazione, sembra essere bloccato in un ciclo infinito. Ecco quello che ho finora:

def _extract_publication_date(html): 
    root = html5lib.parse(html, treebuilder='lxml', namespaceHTMLElements=False) 
    publication_date_string = root.xpath("//a/@data-datetime")[0] 
    return parse_date(publication_date) 


def _update_tip(tip): 
    tip.publication_date = _extract_publication_date(tip.rendered_html) 
    tip.save() 


def upgrade(): 
    op.add_column('tip', sa.Column('publication_date', sa.DateTime(timezone=True))) 
    tips = Tip.query.all() 
    map(tips, _update_tip) 


def downgrade(): 
    op.drop_column('tip', 'publication_date') 
+0

Come fai a sapere che è bloccato in un ciclo infinito? –

+1

Se 'Tip.query' non sta usando la stessa sessione di' op', allora ci saranno 2 transazioni, con 'SELECT' si è bloccato in attesa del commit 'ALTER TABLE'. Ad ogni modo, penso che sia più pulito spostare la porzione ORM sul proprio script, da eseguire manualmente dopo "aggiornamento alembic". – sayap

+0

@ X-Istence Non so se è bloccato in un ciclo infinito. I ** DO ** so che il comando non ritorna mai. –

risposta

1

Continuare dai commenti, si può provare qualcosa di simile:

import sqlalchemy as sa 


tip = sa.sql.table(
    'tip', 
    sa.sql.column('id', sa.Integer), 
    sa.sql.column('publication_date', sa.DateTime(timezone=True)), 
) 


def upgrade(): 
    mappings = [ 
     (x.id, _extract_publication_date(x.rendered_html)) 
     for x in Tip.query 
    ] 

    op.add_column('tip', sa.Column('publication_date', sa.DateTime(timezone=True))) 

    exp = sa.sql.case(value=tip.c.id, whens=(
     (op.inline_literal(id), op.inline_literal(publication_date)) 
     for id, publication_date in mappings.iteritems() 
    )) 

    op.execute(tip.update().values({'publication_date': exp})) 


def downgrade(): 
    op.drop_column('tip', 'publication_date') 
4

Quello che ha funzionato per me è quello di ottenere una sessione effettuando le seguenti operazioni:

+0

Questo * tipo di * ha funzionato per me, anche se c'erano degli errori che dicevano che i miei modelli erano già legati a una sessione. – killthrush

4

Dopo un po 'di sperimentazione con la risposta di @ velochy, ho optato per qualcosa come il seguente schema per l'utilizzo di SqlAlchemy all'interno di Alembic. Questo ha funzionato grande per me e probabilmente potrebbe servire come una soluzione generale per la domanda del PO:

from sqlalchemy.orm.session import Session 
from alembic import op 

def upgrade(): 
    # Attach a sqlalchemy Session to the env connection 
    session = Session(bind=op.get_bind()) 

    # Perform arbitrarily-complex ORM logic 
    instance1 = Model1(foo='bar') 
    instance2 = Model2(monkey='banana') 

    # Add models to Session so they're tracked 
    session.add(instance1) 
    session.add(instance2) 

def downgrade(): 
    # Attach a sqlalchemy Session to the env connection 
    session = Session(bind=op.get_bind()) 

    # Perform ORM logic in downgrade (e.g. clear tables) 
    session.query(Model2).delete() 
    session.query(Model1).delete() 

Questo approccio sembra per gestire le transazioni in modo corretto. Spesso durante il lavoro su questo, vorrei generare eccezioni DB e avrebbero rotolare le cose indietro come previsto.

+1

Vale la pena notare che questa tecnica può essere sconsigliata se i modelli cambiano di frequente. Quando i modelli cambiano, possono interrompere le vecchie migrazioni che presuppongono che i modelli abbiano una certa forma. – killthrush

Problemi correlati