我在当前项目中使用postgresql9.4 + flask + sqlalchemy。为了进行数据库迁移,我决定使用sqlalchemy-migrate。但我遇到了这个工具没有正确表示字段默认值的问题。为了简化我的问题,我解决了这个问题。我的项目看起来像这样:
flask_sqlalchemy_migration
├── app
│ └── __init__.py
├── config.py
├── db_create.py
└── db_migrate.py
./应用/ __初始化__。PY
from flask import Flask
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config.from_object('config')
db = SQLAlchemy(app)
class Base(db.Model):
# __abstract__ = True
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
./ config.py
import os
basedir = os.path.abspath(os.path.dirname(__file__))
# database settings
DBMS = 'postgresql'
adapter = 'psycopg2'
user = 'flask_sqlalchemy_migration_db_user'
host = 'localhost'
port = '5432'
database = 'flask_sqlalchemy_migration_db'
SQLALCHEMY_DATABASE_URI = DBMS + '+' + adapter + '://' + user + '@' + host + ':' + port + '/' + database
SQLALCHEMY_MIGRATE_REPO = os.path.join(basedir, 'db_repository')
SQLALCHEMY_TRACK_MODIFICATIONS = True
./ db_create.py
#!env/bin/python
from migrate.versioning import api
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
from app import db
import os.path
db.create_all()
if not os.path.exists(SQLALCHEMY_MIGRATE_REPO):
api.create(SQLALCHEMY_MIGRATE_REPO, 'database repository')
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
else:
api.version_control(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO,
api.version(SQLALCHEMY_MIGRATE_REPO))
./ db_migrate.py
#!env/bin/python
import imp
from migrate.versioning import api
from app import db
from config import SQLALCHEMY_DATABASE_URI
from config import SQLALCHEMY_MIGRATE_REPO
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
migration = SQLALCHEMY_MIGRATE_REPO + ('/versions/%03d_migration.py' % (v+1))
tmp_module = imp.new_module('old_model')
old_model = api.create_model(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
exec(old_model, tmp_module.__dict__)
script = api.make_update_script_for_model(SQLALCHEMY_DATABASE_URI,
SQLALCHEMY_MIGRATE_REPO,
tmp_module.meta,
db.metadata)
open(migration, "wt").write(script)
api.upgrade(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
v = api.db_version(SQLALCHEMY_DATABASE_URI, SQLALCHEMY_MIGRATE_REPO)
print('New migration saved as ' + migration)
print('Current database version: ' + str(v))
到目前为止一切都很好。我可以运行db_create.py和db_migrate.py,它将使用基表和适当的列创建初始数据库。当我将“modified_at”字段添加到Base模型时,问题就开始了:
class Base(db.Model):
id = db.Column(db.Integer, primary_key=True)
created_at = db.Column(db.DateTime, default=db.func.current_timestamp())
+ modified_at = db.Column(db.DateTime, default=db.func.current_timestamp(),
onupdate=db.func.current_timestamp())
然后,如果我运行./db_migrate.py,我会收到这样的错误:
File "/Users/ruslans/workspace/python/flask_sqlalchemy_migration/db_repository/versions/002_migration.py", line 10
Column('created_at', DateTime, default=ColumnDefault(<sqlalchemy.sql.functions.current_timestamp at 0x108e7b1d0; current_timestamp>)),
^
SyntaxError: invalid syntax
的确,如果我去./db_repository/versions/002_migration.py,我会发现错误的代码:
from sqlalchemy import *
from migrate import *
from migrate.changeset import schema
pre_meta = MetaData()
post_meta = MetaData()
base = Table('base', post_meta,
Column('id', Integer, primary_key=True, nullable=False),
Column('created_at', DateTime, default=ColumnDefault(<sqlalchemy.sql.functions.current_timestamp at 0x108e7b1d0; current_timestamp>)),
Column('modified_at', DateTime, onupdate=ColumnDefault(<sqlalchemy.sql.functions.current_timestamp at 0x108e7b518; current_timestamp>), default=ColumnDefault(<sqlalchemy.sql.functions.current_timestamp at 0x108e7b400; current_timestamp>)),
)
def upgrade(migrate_engine):
# Upgrade operations go here. Don't create your own engine; bind
# migrate_engine to your metadata
pre_meta.bind = migrate_engine
post_meta.bind = migrate_engine
post_meta.tables['base'].columns['modified_at'].create()
def downgrade(migrate_engine):
# Operations to reverse the above upgrade go here.
pre_meta.bind = migrate_engine
post_meta.bind = migrate_engine
post_meta.tables['base'].columns['modified_at'].drop()
如果有人知道它为什么会发生以及我能用它做什么,请告诉我。我用
答案 0 :(得分:0)
只需手动修改您的版本脚本(例如./db_repository/versions/002_migration.py),然后用常规的python代码替换表示形式即可。
因此,将sqlalchemy.sql.functions.current_timestamp替换为:
从应用程序导入数据库... Column('modified_at',DateTime,onupdate = ColumnDefault(db.func.current_timestamp)...