创建表后向 SQLAlchemy 模型添加索引

问题描述 投票:0回答:7

我有一个flask-sqlalchemy模型:

class MyModel(db.Model):
    __tablename__ = 'targets'
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(2048))

该表已创建,并且正在使用。我想在 url 属性上创建索引,因此我将 index=True 传递给它:

url = db.Column(db.String(2048), index=True)

如何让这个索引生效,而不需要删除并重新创建表?

python indexing sqlalchemy
7个回答
52
投票

给出原始问题中的模型类。

class MyModel(db.Model):
    __tablename__ = 'targets'
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(2048))

您不能只添加

index=True
,因为即使您调用
db.Model.metadata.create_all()
,索引也不会在已创建的表上创建。

相反,您需要创建一个独立的

Index
对象,然后再创建它。它看起来像这样:

class MyModel(db.Model):
    __tablename__ = 'targets'
    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(2048))

mymodel_url_index = Index('mymodel_url_idx', MyModel.url)

if __name__ == '__main__':
    mymodel_url_index.create(bind=engine)

现在

engine
的来源将取决于您的 sqlalchemy 配置,但此代码应该传达需要发生的情况的要点。


40
投票

自从提出问题以来,已添加对此的支持。

现在您只需将

index=True
添加到现有列,并自动生成迁移。

检查了以下软件包版本:

alembic==1.0.10
SQLAlchemy==1.3.4
SQLAlchemy-Utils==0.34.0
Flask-SQLAlchemy==2.4.0
Flask-Migrate==2.5.2

3
投票

请注意,这是不正确且过于复杂的答案

正确的方法是使用

index.create
,正如这里所说。


首先确保您拥有数据库的最新快照,并且能够从该快照恢复数据库。

对于中型和大型项目(您可能需要同时支持多个版本并安装在多个环境中的项目),有一个特殊的过程,它是数据库管理生命周期的一部分,称为“数据库迁移”。数据库迁移包括对现有架构的更改。 SQLAlchemy 不支持开箱即用的迁移。

有两种 SQLAlchemy 兼容的数据库迁移工具可用:

在 SQLAlchemy 文档页面中查看更多信息和这些工具的链接:通过迁移更改架构

但是,如果您正在开发小型项目,我建议您从数据库命令行实用程序或通过 python 脚本中的connection.execute() 手动运行 ALTER TABLE DDL 查询。

在我现在正在使用的生产应用程序中,我们仅支持一个最新版本的应用程序。对于每个数据库架构更改,我们都会执行以下步骤:

  • 制作生产数据库的快照
  • 在开发环境中加载此快照
  • 更新sqlalchemy数据模型模块
  • 准备并运行更改表查询并保存此查询以供稍后使用
  • 对代码进行其他相关更改
  • 在开发环境上运行测试
  • 将最新版本的代码部署到生产环境
  • 在生产中更改表

我还使用以下技巧来生成创建表/索引查询: 我将我的应用程序指向全新的数据库,启用 sqlalchemy 查询的日志记录并运行

metadata.create_all()
- 因此在日志(或 STDOUT)中我看到由 sqlalchemy 生成的创建查询

根据您使用的数据库系统,索引创建查询会略有不同。 通用查询如下所示:

create index targets_i on targets(url);


1
投票

你必须清楚两个阶段:

  1. 您的 ORM:您的数据模型是什么样子
  2. 您的迁移进度:将设计中的数据模型转换为数据库表

Add

index=True
仅更新您设计的 ORM。您应该检查您的迁移进度 - 他们如何根据您的 ORM 创建数据库表。您没有提到迁移,所以我认为您忘记了它们。

我建议尝试积极管理您的迁移流程 - 例如了解 Alembic 及其工作原理。


-2
投票

我不确定这是否符合最佳实践,但我发现

Alembic
会通知我
__table_args__
中的索引,但实际上并不会在迁移期间为我创建索引。我制作了这个小脚本,可以生成在
__table_args__
属性中找到的新索引。如上所述,它使用
Index.create()
,但如果索引不存在,则会生成新索引。

def create_indexes(db, drop_index=False):
    """
    Creates all indexes on models in project if they do not exists already. Assumes all models
    inherit from RequiredFields class, otherwise will need to adjust search for subclasses. If the index
    exists SQLAlchemy throws an error and we assume everything is ok. 
    :param db: The app db object, acts as the engine param for the Index.create()
    :param drop_index: specifies whether the indexes should be dropped or created
    :return:
    """
    from application.base_models import RequiredFields
    from sqlalchemy import Index
    from sqlalchemy.exc import ProgrammingError
    for klass in RequiredFields.__subclasses__():
        if hasattr(klass, '__table_args__'):
            for item in getattr(klass, '__table_args__'):
                if isinstance(item, Index):
                    try:
                        if not drop_index:
                            item.create(db.engine)
                        else:
                            item.drop(db.engine)
                    except ProgrammingError:  # If index exists, creation fails on error
                        pass
    return

这是显示索引的示例类。

class MyModel(RequiredFields):

    __table_args__ = (
         db.Index( ... ),
         db.Index( ... ),
    )

-14
投票

使用flask-migrate。很酷。 添加索引后,只需使用此命令:

python manage.py db migrate

一切正常

© www.soinside.com 2019 - 2024. All rights reserved.