如何将flask-migrate与其他declarative_bases一起使用

Sjo*_*lus 5 sqlalchemy flask-sqlalchemy flask-migrate python-social-auth

我正在尝试在Flask中实现python-social-auth。我已经消除了很多麻烦,同时尝试解释约4篇教程和一本完整的Flask书,并且觉得Flask-migrate陷入了某种僵局。

我目前正在使用以下代码创建python-social-auth在flask-sqlalchemy环境中运行所需的表。

from social.apps.flask_app.default import models
models.PSABase.metadata.create_all(db.engine)
Run Code Online (Sandbox Code Playgroud)

现在,他们显然正在使用某种形式的自己的Base,与我的实际db-object无关。反过来,这会使Flask-Migrate完全错过这些表,并在迁移中将其删除。现在,很明显,我可以从每次删除操作中删除这些db-drop,但是我可以想象,这是一件事会被遗忘的事情之一,突然之间我再也没有OAuth-tie了。

我已经获得了此解决方案,以按照python-social-auth Flask示例的建议使用manage.py-command syncdb的用法(和修改)

Flask-Migrate的作者Miguel Grinberg在回复一个看起来与我非常相似的问题。

我在堆栈溢出时能找到的最接近的是这个,但对我来说,它并没有给我们太多启示,而且答案从未被接受(而且我无法使它起作用,我已经尝试了几次)

供参考,这是我的manage.py:

#!/usr/bin/env python

from flask.ext.script import Server, Manager, Shell
from flask.ext.migrate import Migrate, MigrateCommand


from app import app, db

manager = Manager(app)
manager.add_command('runserver', Server())
manager.add_command('shell', Shell(make_context=lambda: {
    'app': app,
    'db_session': db.session
}))

migrate = Migrate(app, db)
manager.add_command('db', MigrateCommand)

@manager.command
def syncdb():
    from social.apps.flask_app.default import models
    models.PSABase.metadata.create_all(db.engine)
    db.create_all()

if __name__ == '__main__':
    manager.run()
Run Code Online (Sandbox Code Playgroud)

为了明确起见,db init / migration / upgrade命令仅创建我的用户表(显然是迁移表),而不创建社交auth表,而syncdb命令适用于python-social-auth表。

我从github响应中了解到Flask-Migrate不支持此功能,但是我想知道PSABase-table中是否有办法摆弄它们,以便由发送到Migrate中的db对象拾取它们。

任何建议欢迎。

(也是第一次发布者。我觉得我终于来这里发表之前已经做了很多研究,并尝试了很多解决方案。如果我错过了SO准则中明显的内容,请不要犹豫在私人讯息中指出这一点,我会很乐意)

Sjo*_*lus 5

在米格尔在这里提供了有用的答案后,我得到了一些新的关键词来研究。我最终找到了一个有用的 github 页面,其中进一步参考了Alembic bitbucket 网站等,这给了我很大帮助。

最后,我对 Alembic 迁移 env.py 文件执行了以下操作:

from sqlalchemy import engine_from_config, pool, MetaData

[...]

# add your model's MetaData object here
# for 'autogenerate' support
# from myapp import mymodel
# target_metadata = mymodel.Base.metadata
from flask import current_app
config.set_main_option('sqlalchemy.url',
                       current_app.config.get('SQLALCHEMY_DATABASE_URI'))

def combine_metadata(*args):
    m = MetaData()
    for metadata in args:
        for t in metadata.tables.values():
            t.tometadata(m)
    return m

from social.apps.flask_app.default import models

target_metadata = combine_metadata(
    current_app.extensions['migrate'].db.metadata,
    models.PSABase.metadata)
Run Code Online (Sandbox Code Playgroud)

这似乎工作得绝对完美。


Mig*_*uel 2

问题是您有两组模型,每组都有不同的 SQLAlchemy 元数据对象。PSA 的模型是直接从 SQLAlchemy 生成的,而您自己的模型是通过 Flask-SQLAlchemy 生成的。

Flask-Migrate 只能看到通过 Flask-SQLAlchemy 定义的模型,因为db您提供给它的对象只知道这些模型的元数据,它对绕过 Flask-SQLAlchemy 的其他 PSA 模型一无所知。

所以,是的,最终结果是每次生成迁移时,Flask-Migrate/Alembic 都会在数据库中找到这些 PSA 表并决定删除它们,因为它看不到它们的任何模型。

我认为解决您问题的最佳解决方案是将 Alembic 配置为忽略某些表。为此,您可以使用存储在迁移目录中的模块中的include_object配置。env.py基本上,您将编写一个函数,Alembic 在生成迁移脚本时每次遇到新实体时都会调用该函数。False当相关对象是这些 PSA 表之一以及True其他所有对象时,该函数将返回。

更新:您在编写的响应中包含的另一种选择是将两个元数据对象合并为一个,然后 Alembic 一起检查应用程序和 PSA 中的模型。

我并不反对将多个元数据对象合并为一个的技术,但我认为应用程序跟踪不属于您的模型中的迁移并不是一个好主意。很多时候,Alembic 无法准确捕获迁移,因此您可能需要在应用生成的脚本之前对其进行较小的更正。对于您的模型,您能够检测到有时会出现在迁移脚本中的这些不准确之处,但是当模型不是您的时,我认为您可能会错过一些东西,因为您对这些模型中的更改不够熟悉模型对 Alembic 生成的脚本进行良好的审查。

因此,我认为使用我建议的include_object配置将第三方模型排除在迁移之外是一个更好的主意。这些模型应根据第三方项目的说明进行迁移。