without query examples example python sqlalchemy flask-sqlalchemy alembic

python - query - Alambique: ¿Cómo migrar el tipo personalizado en un modelo?



sql alchemy migrate (3)

Mi modelo de User es

class User(UserMixin, db.Model): __tablename__ = ''users'' # noinspection PyShadowingBuiltins uuid = Column(''uuid'', GUID(), default=uuid.uuid4, primary_key=True, unique=True) email = Column(''email'', String, nullable=False, unique=True) _password = Column(''password'', String, nullable=False) created_on = Column(''created_on'', sa.types.DateTime(timezone=True), default=datetime.utcnow()) last_login = Column(''last_login'', sa.types.DateTime(timezone=True), onupdate=datetime.utcnow())

donde GUID es un tipo personalizado como se describe en sqlalchemy docs (Exactamente igual)

Ahora cuando corro

alembic revision --autogenerate -m "Added initial table"

Obtengo mi upgrade() como

def upgrade(): ### commands auto generated by Alembic - please adjust! ### op.create_table(''users'', sa.Column(''uuid'', sa.GUID(), nullable=False), sa.Column(''email'', sa.String(), nullable=False), sa.Column(''password'', sa.String(), nullable=False), sa.Column(''created_on'', sa.DateTime(timezone=True), nullable=True), sa.Column(''last_login'', sa.DateTime(timezone=True), nullable=True), sa.PrimaryKeyConstraint(''uuid''), sa.UniqueConstraint(''email''), sa.UniqueConstraint(''uuid'') ) ### end Alembic commands ###

pero durante la aplicación de actualización -> alembic upgrade head , veo

File "alembic/versions/49cc74d0da9d_added_initial_table.py", line 20, in upgrade sa.Column(''uuid'', sa.GUID(), nullable=False), AttributeError: ''module'' object has no attribute ''GUID''

¿Cómo puedo hacer que funcione con GUID / tipo personalizado aquí?


Puede reemplazar sa.GUID() con sa.CHAR(32) o UUID() (luego de agregar la línea from sqlalchemy.dialects.postgresql import UUID ) dependiendo del dialecto.

Sustituirlo con GUID() (después de agregar la línea from your.models.custom_types import GUID ) también funcionará, pero el script de actualización está vinculado al código de su modelo, lo que puede no ser una buena idea.


Tuve un problema similar y lo resolvió de la siguiente manera:

Supongamos que tiene el siguiente módulo my_guid , que contiene (de la página que ya citó, con modificaciones menores de nombres):

import uuid as uuid_package from sqlalchemy.dialects.postgresql import UUID as PG_UUID from sqlalchemy import TypeDecorator, CHAR class GUID(TypeDecorator): impl = CHAR def load_dialect_impl(self, dialect): if dialect.name == ''postgresql'': return dialect.type_descriptor(PG_UUID()) else: return dialect.type_descriptor(CHAR(32)) def process_bind_param(self, value, dialect): if value is None: return value elif dialect.name == ''postgresql'': return str(value) else: if not isinstance(value, uuid_package.UUID): return "%.32x" % uuid_package.UUID(value) else: # hexstring return "%.32x" % value def process_result_value(self, value, dialect): if value is None: return value else: return uuid_package.UUID(value)

Si usa este GUID en sus modelos, solo tiene que agregar tres líneas en alembic/env.py :

from my_guid import GUID import sqlalchemy as sa sa.GUID = GUID

Eso funcionó para mí. ¡Espero que ayude!


Usar la función __repr__ de la clase de atributo __repr__ me funcionó para la mayoría de los tipos personalizados. Me parece más limpio tener la definición de migración contenida dentro de la clase en lugar de preocuparse por poner importaciones en su env.py o scripts.py.mako . Además, hace que sea fácil mover su código entre módulos.

Class GUID(types.TypeDecorator) impl = CHAR def __repr__(self): return self.impl.__repr__() # You type logic here.

La automigración producirá CHAR(length=XXX) .