sqlalchemy-migration генерирует неверный скрипт для db.func.current_timestamp()

Я использую postgresql9.4+flask+sqlalchemy в своем текущем проекте. Для миграции базы данных я решил использовать sqlalchemy-migrate. Но я столкнулся с проблемой, что этот инструмент неправильно представляет значение по умолчанию для поля. Чтобы упростить мой вопрос, я изолировал проблему. Мой проект выглядит так:

flask_sqlalchemy_migration
├── app
│   └── __init__.py
├── config.py
├── db_create.py
└── db_migrate.py

./приложение/__init__.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» в базовую модель:

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.11.1
  • Flask-SQLAlchemy == 2.1
  • psycopg2==2.6.2
  • SQLAlchemy==1.1.2
  • sqlalchemy-migrate==0.10.0

person RuslanSh    schedule 24.10.2016    source источник


Ответы (1)


Просто измените свой сценарий версии (например, ./db_repository/versions/002_migration.py) вручную и замените представления обычным кодом Python.

Итак, замените sqlalchemy.sql.functions.current_timestamp на:

из приложения import db... Column('modified_at', DateTime, onupdate=ColumnDefault(db.func.current_timestamp)...

person Andrii Danyleiko    schedule 09.11.2019