以编程方式获取Alembic数据库版本

时间:2014-06-26 13:05:27

标签: python sqlalchemy alembic

我试图弄清楚如何使用Alembic获取我的数据库版本。我已经将数据库设置为使用alembic并成功执行了升级和降级。我现在想从我自己的python脚本中获取此版本。

我试图创建一个用于执行此操作的函数

def get_current_database_version():
    path = os.path.join(os.path.dirname(__file__), os.path.pardir)
    alembic_cfg = Config(os.path.join(path, 'alembic.ini'))
    current_rev = command.current(alembic_cfg, head_only=True)
    return current_rev

此函数返回NoSectionError: No section: 'formatters'

然后我去了我的alembic.ini文件,检查它是否有格式化区域。这是我的alembic.ini文件:

# A generic, single database configuration.

[alembic]
# path to migration scripts
script_location = alembic
pyramid_config_file = ../../development.ini

# template used to generate migration files
# file_template = %%(rev)s_%%(slug)s

# max length of characters to apply to the
# "slug" field
#truncate_slug_length = 40

# set to 'true' to run the environment during
# the 'revision' command, regardless of autogenerate
# revision_environment = false

# set to 'true' to allow .pyc and .pyo files without
# a source .py file to be detected as revisions in the
# versions/ directory
# sourceless = false

sqlalchemy.url = sqlite:///%(here)s/mgo.sqlite


# Logging configuration
[loggers]
keys = root,sqlalchemy,alembic

[handlers]
keys = console

[formatters]
keys = generic

[logger_root]
level = WARN
handlers = console
qualname =

[logger_sqlalchemy]
level = WARN
handlers =
qualname = sqlalchemy.engine

[logger_alembic]
level = INFO
handlers =
qualname = alembic

[handler_console]
class = StreamHandler
args = (sys.stderr,)
level = NOTSET
formatter = generic

[formatter_generic]
format = %(levelname)-5.5s [%(name)s] %(message)s
datefmt = %H:%M:%S

任何人都知道我做错了什么?感谢

编辑:

这是我尝试使用MigrationContext来解决问题:

def get_database_revision():
    engine = create_engine("sqlite:///../mgo.db")
    conn = engine.connect()
    context = MigrationContext.configure(conn)
    current_rev = context.get_current_revision()
    return current_rev

它连接但没有返回。使用sqlite浏览器我可以看到数据库中的版本没有设置为none。

8 个答案:

答案 0 :(得分:8)

您可以MigrationContext使用get the current version

from alembic.migration import MigrationContext
from sqlalchemy import create_engine

engine = create_engine("postgresql://mydatabase")
conn = engine.connect()

context = MigrationContext.configure(conn)
current_rev = context.get_current_revision()

env.py内,你可以使用:

from alembic import context
migration_context = context.get_context()
current_rev = context.get_current_revision()

最后,它基本上归结为连接到数据库并查看alembic_version表。它包含迁移版本作为值以及数据库当前所在的值(根据alembic)。所以你可以按照你想要的方式编写代码,只要这样你最终会做什么。

答案 1 :(得分:2)

这个问题很古老,但是我有一个解决方案,我认为它比到目前为止给出的解决方案简单一些。

主要观察结果是,在调用command.current时,Alembic不使用Python内置的print函数,而是在config对象上使用print_stdout方法。因此,要捕获输出,只需重载print_stdout函数!这对我有用:

def get_current_database_version():
    path = os.path.join(os.path.dirname(__file__), os.path.pardir)
    alembic_cfg = Config(os.path.join(path, 'alembic.ini'))

    captured_text = None
    def print_stdout(text, *arg):
        nonlocal captured_text
        captured_text = text

    alembic_cfg.print_stdout = print_stdout
    command.current(alembic_cfg)
    return captured_text

答案 2 :(得分:1)

只想投入2美分。

首先,可能是MigrationContext对您没有用,因为您没有连接到正确的数据库。从我看到的文档中,create_engine将为您创建一个db,如果它找不到您指定的文件。这可能发生了,因为在您的示例中,您使用的是相对路径,这很容易混淆。

其次,最让我痛苦的是

command.current(alembic_cfg, head_only=True)

实际上只有显示当前版本,对我来说似乎是在eclipse中将值打印到控制台。函数本身总是返回None,这有点烦人,这就是需要MigrationContext的原因。

此外,如果您要检查当前版本,因为您想要了解数据库的状态而不实际更新它,那么您将需要使用ScriptDirectory http://alembic.readthedocs.org/en/latest/api/script.html#alembic.script.ScriptDirectory 及其各种方法,以确定MigrationContext返回的版本是否是当前头部,或者它是否甚至有效。

答案 3 :(得分:1)

我建议使用stdout Config()对象参数(请参见here)来允许将sys.stdout重定向到StringIO缓冲区,如下所示:

output_buffer = io.StringIO()
alembic_cfg = alembic_Config('/path/to/alembic.ini', stdout=output_buffer)
alembic_command.current(alembic_cfg)
output = output_buffer.getvalue()
print(output)

答案 4 :(得分:1)

仅基于James Fennel's答案,在获取历史记录的情况下,它只会输出一行。如果您希望所有输出(作为列表),可以执行以下操作:

def get_current_database_history(input_cfg, start_rev=None):
    captured_text = []
    def print_stdout(text, *arg):
        nonlocal captured_text
        captured_text.append(text)
    input_cfg.print_stdout = print_stdout
    if start_rev:
        command.history(input_cfg, rev_range="{}:".format(start_rev))
    else:
        command.history(input_cfg)
    return captured_text

答案 5 :(得分:1)

from alembic.config import Config
from alembic import command
from alembic.script import ScriptDirectory
from alembic.runtime.environment import EnvironmentContext


class DBMigrations:

    def __init__(self):
        self.alembic_cfg = Config("./alembic.ini")
        self.alembic_cfg.set_main_option('sqlalchemy.url', DATABASE_URL)
        self.script = ScriptDirectory.from_config(self.alembic_cfg)

    def get_db_version(self):
        current_version = ""

        def display_version(rev, context):
            for rev in self.script.get_all_current(rev):
                nonlocal current_version
                current_version = rev.cmd_format(verbose=False)
            return []

        with EnvironmentContext(self.alembic_cfg, self.script, fn=display_version, dont_mutate=True):
            self.script.run_env()
        return current_version.split()[0]

答案 6 :(得分:0)

这是一个临时修复程序,它返回正确的版本号。

def get_database_revision():
    s = select(['version_num'],from_obj='alembic_version')
    result = DBSession.execute(s).fetchone()
    return result['version_num']

如果没有找到版本号,则此函数返回None。

答案 7 :(得分:-1)

黑客!使用sh,在正确的目录中,它就像:

一样简单
>>> from sh import alembic
>>> alembic("current")
4cad21a83709 (head)