Warning: file_get_contents(/data/phpspider/zhask/data//catemap/2/python/315.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python Alembic:如何迁移模型中的自定义类型?_Python_Sqlalchemy_Flask Sqlalchemy_Alembic - Fatal编程技术网

Python Alembic:如何迁移模型中的自定义类型?

Python Alembic:如何迁移模型中的自定义类型?,python,sqlalchemy,flask-sqlalchemy,alembic,Python,Sqlalchemy,Flask Sqlalchemy,Alembic,我的用户型号为 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, nul

我的
用户
型号为

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())
其中
GUID
是中所述的自定义类型(完全相同)

现在当我跑的时候

alembic revision --autogenerate -m "Added initial table"
我的
升级()
如下

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 ###
但在应用升级->
alembic升级头时,我看到

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'

如何在这里使用
GUID
/自定义类型?

您可以根据方言将
sa.GUID()
替换为
sa.CHAR(32)
UUID()
(从sqlalchemy.dialogs.postgresql import UUID添加导入行
后)


将其替换为
GUID()
(从.models.custom\u types import GUID中添加导入行
)也可以,但是升级脚本绑定到模型代码,这可能不是一件好事。

我遇到了类似的问题,并按如下方式解决了它:

假设您有以下模块
my_guid
,其中包含(从您已经引用的页面中,经过少量命名修改):

如果在模型中使用此GUID,则只需在
alembic/env.py
处添加三行:

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

这对我很管用。希望有帮助

对于大多数自定义类型,使用
impl
属性类的
\uuuuuu repr\uuuu
函数对我很有效。我发现将迁移定义包含在类中,而不用担心将导入放入
env.py
scripts.py.mako
,这样会更干净。此外,它还可以轻松地在模块之间移动代码

Class GUID(types.TypeDecorator)
    impl = CHAR

    def __repr__(self):
        return self.impl.__repr__()

    # You type logic here.

自动迁移将生成
CHAR(length=XXX)
我的解决方案使用
sqlalchemy\u utils.types.uuid.UUIDType
,如果您在没有
uuid
类型的数据库上,则使用
CHAR(32)
BINARY(16)
来表示uuid。您需要在迁移中考虑到这一点,迁移必须在没有
UUID
类型的数据库上创建
CHAR(32)/BINARY(16)
,在有它的数据库上创建
UUIDType

我的SQLAlchemy类如下所示:

来自sqlalchemy\u utils.types.uuid导入UUIDType
从sqlalchemy导入字符、列、整数
Base=声明性_Base()
def get_uuid():
返回str(uuid.uuid4())
类仪表板(基本):
__tablename_uuu=‘仪表盘’
id=列(整数,主键=True)
uuid=列(UUIDType(binary=False),默认值=get\u uuid)
实际的批处理操作如下所示(支持SQLite、MySQL和Postgres):

from superset import db#设置SQLAlchemy连接
def升级():
bind=op.get_bind()
session=db.session(bind=bind)
db_type=session.bind.dialogue.name
def add_uuid_列(列名称,类型):
“”“将uuid列添加到给定表”“”
将op.batch\u alter\u表(col\u name)作为批处理操作:
批处理操作添加列(列('uuid',UUIDType(二进制=False),默认=get\uuid))
对于会话中的查询(\u类型):
s、 uuid=get_uuid()
会话。合并(个)
如果db_类型!='postgresql':
将op.batch\u alter\u表(col\u name)作为批处理操作:
批处理操作更改列('uuid',现有类型=字符(32),
新列(名称='uuid',可空=假)
批处理操作创建唯一约束('uq_uuid',['uuid'])
session.commit()
添加_uuid_列(“仪表板”,仪表板)
session.close()

希望这有帮助

但是如果我使用
sqlite
的话,这会破坏测试,而且它不会是一致的,不是吗?我真的不太喜欢在测试中使用
sqlite
,因为测试环境应该紧跟产品。除此之外,您是否针对多种方言部署了相同的代码?无论如何,我希望迁移脚本在某个时间点与实际模式保持一致,与代码的一致性受到谴责,因为代码永远在变化。我想我会关心sqlite用于我的测试,因为它们可以在内存中运行,但是你说的话也很有道理,让我试试你说的,然后回答你。我完全同意你的观点,并且有PostgreSQL用于
dev
test
环境,你的回答对我有很大帮助@sayap。谢谢你为我做了很多工作。谢谢。第二,这对我来说很有效,而关于这个和其他问题的许多其他答案都不起作用。谢谢我不认为这一点单独起作用,至少在Alembic 1.4.3和SQLAlchemy ORM中是这样。假设您的自定义类型是在
app.models
中定义或导入的。生成的迁移将只包含
app.models.CHAR
,而不是
app.models.GUID
。可能在回答此问题后默认渲染已更改?
Class GUID(types.TypeDecorator)
    impl = CHAR

    def __repr__(self):
        return self.impl.__repr__()

    # You type logic here.