2012-08-15 4 views
20

Ich möchte einige Datenbankdaten im Rahmen eines Alembic-Upgrades ändern.Ändern von Daten im Rahmen eines Alembic-Upgrades

Ich dachte, ich könnte nur einen Code in der Aktualisierung meiner Migration hinzufügen, aber die folgenden fehlschlägt:

def upgrade(): 
    ### commands auto generated by Alembic - please adjust! ### 
    op.add_column('smsdelivery', sa.Column('sms_message_part_id', sa.Integer(), sa.ForeignKey('smsmessagepart.id'), nullable=True)) 
    ### end Alembic commands ### 

    from volunteer.models import DBSession, SmsDelivery, SmsMessagePart 

    for sms_delivery in DBSession.query(SmsDelivery).all(): 
     message_part = DBSession.query(SmsMessagePart).filter(SmsMessagePart.message_id == sms_delivery.message_id).first() 
     if message_part is not None: 
      sms_delivery.sms_message_part = message_part 

mit dem folgenden Fehler:

sqlalchemy.exc.UnboundExecutionError: Could not locate a bind configured on mapper Mapper|SmsDelivery|smsdelivery, SQL expression or this Session 

ich wirklich nicht diesen Fehler zu verstehen . Wie kann ich das beheben oder mache Operationen wie diese nicht möglich?

+1

Können Sie die Lösung posten, wenn Sie dies gelöst haben? – Devi

Antwort

15

Es ist schwer zu verstehen, was genau Sie mit dem von Ihnen bereitgestellten Code-Auszug erreichen möchten. Aber ich werde versuchen zu erraten. Die folgende Antwort basiert auf meiner Vermutung.

Zeile 4 - Sie importieren Dinge (DBSession, SmsDelivery, SmsMessagePart) von Ihren Modulen und dann versuchen Sie, mit diesen Objekten zu arbeiten, wie Sie es in Ihrer Anwendung tun.

Der Fehler zeigt, dass SmsDelivery ein Mapper-Objekt ist - also auf eine Tabelle zeigt. Mapper-Objekte sollten an eine gültige sqlalchemy-Verbindung gebunden sein.

Das sagt mir, dass Sie die Initialisierung von DB-Objekten (Verbindung und Bindung dieser Verbindung zu Mapper-Objekten) übersprungen haben, wie Sie normalerweise in Ihrem Anwendungscode tun.

DBSession sieht aus wie SQLAlchemy-Sitzungsobjekt - es sollte auch Verbindungsbindung haben.

Alembic hat bereits Verbindung bereit und offen - für Änderungen an DB-Schema, die Sie anfordern mit op. * Methoden.

So sollte es möglich sein, diese Verbindung zu bekommen.

Nach Alembic manueller op.get_bind() wird die aktuell Verbindungs ​​binden zurück:
Für vollständige Interaktion mit einer angeschlossenen Datenbank, verwenden Sie die „bind“, erhältlich von Kontext:

from alembic import op 
connection = op.get_bind() 

Sie können also verwenden Diese Verbindung, um Ihre Abfragen in db auszuführen.

PS. Ich würde annehmen, dass Sie einige Änderungen an Daten in Ihrer Tabelle vornehmen wollten. Sie können versuchen, diese Änderung in einer Aktualisierungsabfrage zu formulieren. Alembic verfügt über eine spezielle Methode, um solche Änderungen auszuführen - Sie müssen also keine Verbindung herstellen.
alembic.operations.Operations.execute

execute(sql, execution_options=None) 

Führen Sie die angegebenen SQL den aktuellen Migrationskontext.

In einem SQL-Skriptkontext wird die Anweisung direkt an den Ausgabestream gesendet. Es gibt jedoch kein Rückgabeergebnis, da diese Funktion darauf ausgerichtet ist, ein Änderungsskript zu generieren, das im "Offline" -Modus ausgeführt werden kann.

Parameter: sql - Jeder Ausdruck Rechts SQLAlchemy, einschließlich:

  • eine Zeichenfolge ein sqlalchemy.sql.expression.text() konstruieren.
  • eine sqlalchemy.sql.expression.insert() Konstrukt.
  • a sqlalchemy.sql.expression.update(),
  • sqlalchemy.sql.expression.insert() oder
  • sqlalchemy.sql.expression.delete() konstruieren. So ziemlich alles das ist "ausführbar" wie in SQL Expression Language Tutorial beschrieben.
+0

Ich suche einen Weg, um meine bestehenden Daten zu aktualisieren! Ihre Antwort sollte die akzeptierte Antwort sein. Vielen Dank! – swdev

0

Sie müssen auch Base importieren und dann

Base.metatada.bind = op.get_bind() 

und danach können Sie Ihre Modelle wie immer ohne Fehler verwenden.

12

Seine erwähnenswert, dass, wenn Sie dies tun, werden Sie wahrscheinlich eine Kopie des ORM-Modell innerhalb die Migration, wie dies festgehalten werden soll:

class MyType(Base): 
    __tablename__ = 'existing_table' 
    __table_args__ = {'extend_existing': True} 
    id = Column(Integer, ...) 
    .. 

def upgrade(): 
    Base.metadata.bind = op.get_bind() 

    for item in Session.query(MyType).all(): 
    ... 

Sonst wirst du unweigerlich in einer Situation am Ende wo Sie Orm-Modell Änderungen und vorherige Migrationen nicht mehr funktionieren.

Beachten Sie insbesondere, dass Sie Base erweitern möchten, nicht den Basistyp selbst (app.models.MyType), da Ihr Typ möglicherweise irgendwann verschwindet und Ihre Migrationen erneut fehlschlagen.

Verwandte Themen