2013-01-19 11 views
15

Ho un modello pallone-sqlalchemy:Aggiunta di indici ai modelli SQLAlchemy dopo la creazione delle tabelle

class MyModel(db.Model): 
__tablename__ = 'targets' 
id = db.Column(db.Integer, primary_key=True) 
url = db.Column(db.String(2048)) 

La tabella è già stato creato, ed è in uso. Voglio creare un indice per l'attributo url, così mi passa index = True ad esso:

url = db.Column(db.String(2048), index=True) 

Come posso fare questo indice abbia effetto, senza eliminare e ricreare il tavolo?

risposta

2

prega di notare che questo non è corretto e più complicata risposta

Il modo giusto è quello di utilizzare index.create come è stato detto here.


Prima di tutto assicurarsi di disporre dell'ultima istantanea del database e di ripristinare il database da questa istantanea.

Per progetti di medie e grandi dimensioni (quelli che potrebbero essere necessari per supportare più versioni contemporaneamente e sono installati su più ambienti), esiste una procedura speciale che fa parte del ciclo di vita della gestione del database chiamata "migrazione del database". Le migrazioni DB includono modifiche allo schema esistente. SQLAlchemy non supporta la migrazione fuori dalla scatola.

ci sono due SQLAlchemy strumenti di migrazione di database compatibili disponibili:

Tutte le informazioni e collegamenti a questi strumenti nella pagina di documentazione SQLAlchemy: Altering Schemas through Migrations.

Tuttavia, se si sta lavorando su un progetto di piccole dimensioni, suggerire di eseguire manualmente la query DDL ALTER TABLE dall'utilità della riga di comando del database o tramite connection.execute() nello script python.

Nell'applicazione di produzione su cui sto lavorando in questo momento, supportiamo solo una versione più recente dell'applicazione.Per ogni modifica dello schema del database che facciamo le seguenti operazioni:

  • fare una fotografia istantanea del database di produzione
  • carico questa istantanea su ambiente di sviluppo
  • modulo di modello di dati sqlalchemy
  • aggiornamento
  • preparare ed eseguire alter interrogazione tavolo e salvare questa query per un successivo
  • apportare altre modifiche relative al codice
  • test eseguiti su ambiente dev
  • distribuire ultima versione del codice per la produzione
  • alterano tavolo sulla produzione

Anche io sto usando il seguente trucco per generare creare query tavolo/index: indico la mia domanda di marca nuovo database, abilitare la registrazione di query SQLAlchemy ed eseguire metadata.create_all() - così nei registri (o STDOUT) vedo creare query generata da sqlalchemy

a seconda del sistema di database che si sta utilizzando query di creazione dell'indice sarà po 'diverso. query standard sarebbe simile a questa:

create index targets_i on targets(url); 
+0

scusa, questa risposta è errata. ALTER TABLE non è utilizzato per gli indici. SQLAlchemy supporta "CREATE INDEX" molto direttamente usando 'Index.create()', così come con il costrutto DDL 'CreateIndex' per situazioni di scripting più elaborate. Non c'è bisogno di prendere l'output "create_all()" o qualcosa del genere. – zzzeek

+0

Grazie per il punto. Sono d'accordo: ho descritto come implementare e supportare l'approccio chiesto in questione. E completamente dimenticato di 'index.create' facile e veloce. – vvladymyrov

6
+8

Questa risposta non dà idea da dove ottenere questo oggetto indice dal codice nella domanda originale. Scansionare i documenti per trovarli è faticoso, e sinceramente poco utile dato che non toccano l'uso dell'API dichiarativa (che viene usata nella domanda originale). Per chiunque sia confuso come me, e non volendo sottoporre a scansione i documenti e il codice sorgente, vedere la mia risposta qui sotto. – brthornbury

15

La risposta attuale top non mi ha aiutato quando sono atterrato qui. Dopo aver letto i documenti (e il codice sorgente) ho trovato questo funziona, spero che aiuti.

Data la classe del modello dalla domanda originale.

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

Non si può semplicemente aggiungere index=True perché, anche se si chiama db.Model.metadata.create_all() l'indice non verrà creato su un tavolo già creato.

Invece, è necessario creare un oggetto indipendente Index e quindi crearlo. Sarà simile a questa:

class MyModel(db.Model): 
    __tablename__ = 'targets' 
    id = db.Column(db.Integer, primary_key=True) 
    url = db.Column(db.String(2048)) 

mymodel_url_index = Index('mymodel_url_idx', MyModel.url) 

if __name__ == '__main__': 
    mymodel_url_index.create(bind=engine) 

Ora, dove engine viene da sarà fino alla configurazione SQLAlchemy, ma questo codice dovrebbe trasmettere l'essenza di ciò che deve accadere.

-1

Non sono sicuro se questo è conforme alle migliori pratiche ma ho trovato Alembic mi informava degli indici nel __table_args__ ma in realtà non li rendono per me durante le migrazioni. Ho creato questo piccolo script in grado di generare nuovi indici trovati nella proprietà __table_args__. Fa uso di Index.create() come menzionato sopra, ma genererà nuovi indici se non esistono.

def create_indexes(db, drop_index=False): 
    """ 
    Creates all indexes on models in project if they do not exists already. Assumes all models 
    inherit from RequiredFields class, otherwise will need to adjust search for subclasses. If the index 
    exists SQLAlchemy throws an error and we assume everything is ok. 
    :param db: The app db object, acts as the engine param for the Index.create() 
    :param drop_index: specifies whether the indexes should be dropped or created 
    :return: 
    """ 
    from application.base_models import RequiredFields 
    from sqlalchemy import Index 
    from sqlalchemy.exc import ProgrammingError 
    for klass in RequiredFields.__subclasses__(): 
     if hasattr(klass, '__table_args__'): 
      for item in getattr(klass, '__table_args__'): 
       if isinstance(item, Index): 
        try: 
         if not drop_index: 
          item.create(db.engine) 
         else: 
          item.drop(db.engine) 
        except ProgrammingError: # If index exists, creation fails on error 
         pass 
    return 

Ecco una classe di esempio che mostra gli indici.

class MyModel(RequiredFields): 

    __table_args__ = (
     db.Index(...), 
     db.Index(...), 
    ) 
-3

Usa flask-migrate.E 'bello. Dopo aver aggiunto l'indice, basta usare questo comando:

python manage.py db migrate 

Tutto funziona bene

0

Se stai usando Alembic, è possibile creare una migrazione per fare questo, ed evitare di aggiungere nel modello a all:

def upgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.create_index('table1_id', 'table1', ['id'], unique=True) 
    op.create_index('table2_id', 'table2', ['id'], unique=True) 
    # ### end Alembic commands ### 

def downgrade(): 
    # ### commands auto generated by Alembic - please adjust! ### 
    op.drop_index('table1_id', table_name='table1') 
    op.drop_index('table2_id', table_name='table2') 
    # ### end Alembic commands ### 
Problemi correlati