python sqlalchemy alembic

python - Modificar datos como parte de una actualización de alambique.



alembic python (3)

Me gustaría modificar algunos datos de la base de datos como parte de una actualización de Alambique.

Pensé que solo podía agregar cualquier código en la actualización de mi migración, pero falla lo siguiente:

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

con el siguiente error:

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

Realmente no estoy entendiendo este error. ¿Cómo puedo solucionar esto o hacer operaciones como esta no es una posibilidad?


Es difícil entender qué es exactamente lo que está tratando de lograr a partir del extracto del código que proporcionó. Pero voy a tratar de adivinar. Así que la siguiente respuesta se basará en mi conjetura.

Línea 4: importa elementos (DBSession, SmsDelivery, SmsMessagePart) desde sus módulos y luego intenta operar con estos objetos como lo hace en su aplicación.

El error muestra que SmsDelivery es un objeto mapeador, por lo que está apuntando a alguna tabla. Los objetos del mapeador deben enlazarse a una conexión sqlalchemy válida.

Lo que me dice que omitió la inicialización de los objetos de base de datos (conexión y enlace de esta conexión a los objetos del asignador) como hace normalmente en el código de su aplicación.

DBSession se parece al objeto de sesión SQLAlchemy: también debería tener un enlace de conexión.

Alembic ya tiene la conexión lista y abierta, para realizar cambios en el esquema db que está solicitando con los métodos op. *.

Así que debería haber manera de obtener esta conexión.

De acuerdo con el manual de Alembic, op.get_bind () devolverá el enlace de conexión actual:
Para una interacción completa con una base de datos conectada, use el "enlace" disponible en el contexto:

from alembic import op connection = op.get_bind()

Por lo tanto, puede utilizar esta conexión para ejecutar sus consultas en db.

PD. Supongo que desea realizar algunas modificaciones a los datos en su tabla. Puede intentar formular esta modificación en una consulta de actualización. Alembic tiene un método especial para ejecutar dichos cambios, por lo que no necesita tratar con la conexión.
alembic.operations.Operations.execute

execute(sql, execution_options=None)

Ejecute el SQL dado usando el contexto de migración actual.

En un contexto de script SQL, la declaración se emite directamente al flujo de salida. Sin embargo, no hay resultados de retorno, ya que esta función está orientada a generar un script de cambio que se pueda ejecutar en modo "fuera de línea".

Parámetros: sql - Cualquier expresión legal de SQLAlchemy, incluyendo:

  • una cadena una construcción sqlalchemy.sql.expression.text ().
  • una construcción sqlalchemy.sql.expression.insert ().
  • un sqlalchemy.sql.expression.update (),
  • sqlalchemy.sql.expression.insert (), o
  • sqlalchemy.sql.expression.delete () construye. Casi todo lo que es "ejecutable" como se describe en el Tutorial de lenguaje de expresión de SQL.

Necesitas importar Base también y luego

Base.metatada.bind = op.get_bind()

Y después de esto puedes usar tus modelos como siempre sin errores.


Vale la pena señalar que si hace esto, probablemente quiera congelar una copia de su modelo de orm dentro de la migración, como esto:

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(): ...

De lo contrario, inevitablemente terminará en una situación en la que modelará los cambios y las migraciones anteriores ya no funcionarán .

En particular, tenga en cuenta que desea extender Base, no el tipo base en sí mismo (app.models.MyType) porque su tipo podría desaparecer en algún momento y, una vez más, las migraciones fallarán.