Quiero agregar un campo a una clase mapeada existente, ¿cómo actualizaría automáticamente la tabla sql? ¿Proporciona sqlalchemy un método para actualizar la base de datos con una nueva columna, si se agrega un campo a la clase?SqlAlchemy agrega un nuevo campo a la clase y crea la columna correspondiente en la tabla
Respuesta
SQLAlchemy no admite actualizaciones automáticas del esquema, pero existe una herramienta de terceros SQLAlchemy Migrate para automatizar las migraciones. Mira aunque "Database schema versioning workflow" chapter para ver cómo funciona.
A veces Migrar es demasiado trabajo; solo desea que la columna se agregue automáticamente cuando ejecuta el código modificado. Entonces aquí hay una función que hace eso.
Advertencias: hurga en las partes internas de SQLAlchemy y tiende a requerir pequeños cambios cada vez que SQLAlchemy se somete a una revisión importante. (Probablemente haya una forma mucho mejor de hacerlo, no soy un experto en SQLAlchemy). Tampoco maneja restricciones.
import logging
import re
import sqlalchemy
from sqlalchemy import MetaData, Table, exceptions
import sqlalchemy.engine.ddl
_new_sa_ddl = sqlalchemy.__version__.startswith('0.7')
def create_and_upgrade(engine, metadata):
"""For each table in metadata, if it is not in the database then create it.
If it is in the database then add any missing columns and warn about any columns
whose spec has changed"""
db_metadata = MetaData()
db_metadata.bind = engine
for model_table in metadata.sorted_tables:
try:
db_table = Table(model_table.name, db_metadata, autoload=True)
except exceptions.NoSuchTableError:
logging.info('Creating table %s' % model_table.name)
model_table.create(bind=engine)
else:
if _new_sa_ddl:
ddl_c = engine.dialect.ddl_compiler(engine.dialect, None)
else:
# 0.6
ddl_c = engine.dialect.ddl_compiler(engine.dialect, db_table)
# else:
# 0.5
# ddl_c = engine.dialect.schemagenerator(engine.dialect, engine.contextual_connect())
logging.debug('Table %s already exists. Checking for missing columns' % model_table.name)
model_columns = _column_names(model_table)
db_columns = _column_names(db_table)
to_create = model_columns - db_columns
to_remove = db_columns - model_columns
to_check = db_columns.intersection(model_columns)
for c in to_create:
model_column = getattr(model_table.c, c)
logging.info('Adding column %s.%s' % (model_table.name, model_column.name))
assert not model_column.constraints, \
'Arrrgh! I cannot automatically add columns with constraints to the database'\
'Please consider fixing me if you care!'
model_col_spec = ddl_c.get_column_specification(model_column)
sql = 'ALTER TABLE %s ADD %s' % (model_table.name, model_col_spec)
engine.execute(sql)
# It's difficult to reliably determine if the model has changed
# a column definition. E.g. the default precision of columns
# is None, which means the database decides. Therefore when I look at the model
# it may give the SQL for the column as INTEGER but when I look at the database
# I have a definite precision, therefore the returned type is INTEGER(11)
for c in to_check:
model_column = model_table.c[c]
db_column = db_table.c[c]
x = model_column == db_column
logging.debug('Checking column %s.%s' % (model_table.name, model_column.name))
model_col_spec = ddl_c.get_column_specification(model_column)
db_col_spec = ddl_c.get_column_specification(db_column)
model_col_spec = re.sub('[(][\d ,]+[)]', '', model_col_spec)
db_col_spec = re.sub('[(][\d ,]+[)]', '', db_col_spec)
db_col_spec = db_col_spec.replace('DECIMAL', 'NUMERIC')
db_col_spec = db_col_spec.replace('TINYINT', 'BOOL')
if model_col_spec != db_col_spec:
logging.warning('Column %s.%s has specification %r in the model but %r in the database' %
(model_table.name, model_column.name, model_col_spec, db_col_spec))
if model_column.constraints or db_column.constraints:
# TODO, check constraints
logging.debug('Column constraints not checked. I am too dumb')
for c in to_remove:
model_column = getattr(db_table.c, c)
logging.warning('Column %s.%s in the database is not in the model' % (model_table.name, model_column.name))
def _column_names(table):
# Autoloaded columns return unicode column names - make sure we treat all are equal
return set((unicode(i.name) for i in table.c))
¡Muchas gracias! Exactamente lo que estaba buscando. – kay
# database.py has definition for engine.
# from sqlalchemy import create_engine
# engine = create_engine('mysql://......', convert_unicode=True)
from database import engine
from sqlalchemy import DDL
add_column = DDL('ALTER TABLE USERS ADD COLUMN city VARCHAR(60) AFTER email')
engine.execute(add_column)
Alembic es el último paquete que ofrece la migración de la base de datos.
- 1. DataTables agrega columna dinámicamente a la tabla
- 2. agregar columna a SQLAlchemy Tabla
- 3. ¿Cómo puedo obtener la columna de tabla correspondiente (td) de un encabezado de tabla (th)?
- 4. ¿Puede SQLAlchemy actualizar la estructura de la tabla?
- 5. La colección backbone.js agrega un elemento vacío cuando se crea?
- 6. Consulta SQL personalizada sin la tabla correspondiente
- 7. JPA: ¿Cómo especifico el nombre de la tabla correspondiente a una clase en tiempo de ejecución?
- 8. SQL - SELECCIONAR MAX() y el campo correspondiente
- 9. Sqlalchemy: evitar la herencia múltiple y tener clase base abstracta
- 10. SQLAlchemy ForeignKey no puede encontrar la tabla
- 11. encriptar columna en la tabla
- 12. Cómo unirse a la misma tabla en sqlalchemy
- 13. MySQL selecciona las filas que no tienen columna correspondiente en la otra tabla
- 14. DataGrid que crea la columna RadioButton
- 15. ¿Cómo se agrega una columna calculada a una tabla?
- 16. SQLAlchemy: longitud máxima de columna
- 17. ¿Application.Restart() crea un nuevo proceso para la aplicación o no?
- 18. Columna específica de orientación en la tabla
- 19. ¿Cómo se crea un índice en la parte de la fecha del campo DATETIME en MySql
- 20. Obtenga el número de filas en la tabla usando SQLAlchemy
- 21. columna de la tabla HTML alinear a la derecha
- 22. Hibernar, herencia de tabla única y usar el campo de la superclase como columna discriminadora
- 23. ¿Derby admite los comentarios de la tabla y la columna?
- 24. Agregar un nuevo archivo en Intellij no agrega a la subversión
- 25. nombres de columna Actualizar en la clase del modelo ActiveRecord
- 26. EF 4.1 Código primera clave externa agrega la columna extra
- 27. MySQL y NHibernate. Cómo corrige el error: ¿La columna 'ReservedWord' no pertenece a la tabla ReservedWords?
- 28. Encontrar el valor máximo en la columna de la tabla
- 29. reemplazar/eliminar campo utilizando sqlalchemy
- 30. Actualizar una columna basada en un campo de otra tabla
hola gracias, pensado tanto ... – jagguli
¿Puedo pedir un nuevo enlace? Ese parece estar muerto. Gracias por adelantado. – Nonsingular