Python SQLAlchemy:反映数据库中断默认/ onupdate方法?

时间:2017-04-12 02:20:20

标签: python postgresql flask sqlalchemy flask-sqlalchemy

我有两个独立的SQLAlchemy接口到Postgres数据库。在Flask应用程序的上下文中,第一个界面包含此模型:

app = create_app() # sets the SQLAlchemy Database URI, etc.
db = SQLAlchemy(app)

class User(db.Model):
    id = db.Column(db.Integer, primary_key=True)
    created_at = db.Column(db.DateTime, default=datetime.datetime.utcnow)
    updated_at = db.Column(db.DateTime, onupdate=datetime.datetime.utcnow)
    name = db.Column(db.String, nullable=False)

第二个接口不是通过Flask - 相反,它是一个侦听特定事件的脚本,在这种情况下,它意味着执行一些计算并更新数据库中的行。为此,我让SQLAlchemy反映现有的数据库:

from sqlalchemy import create_engine, MetaData, Table
from sqlalchemy.orm import mapper, sessionmaker
from sqlalchemy.ext.automap import automap_base
from os import environ

dbPath = "postgresql://" + ...
engine = create_engine(dbPath)

Base = automap_base()
Base.prepare(engine, reflect=True)

metadata = MetaData(engine)

class User(object):
    pass

users = Table('user', metadata, autoload=True, autoload_with=engine)
mapper(User, users)

Session = sessionmaker(bind=engine)
session = Session()

我现在遇到的问题是:当我使用第一个界面创建新条目或更新条目时,事情按预期工作,created_atupdated_at字段适当更新。

但是,当我使用第二个界面 - 导入代码并使用session.query(User)获取条目并进行更新时,updated_at字段不会更改。此外,当我使用此界面创建新用户时,虽然它按预期创建了新行,但它不会填充created_atupdated_at字段。

我的问题:

  1. 为什么会这样?为什么反射似乎打破了default/onupdate方法?
  2. 我该如何解决这个问题?

1 个答案:

答案 0 :(得分:3)

defaultonupdate在Python中完全由客户端处理,因此无法从数据库中反映出来。见"Limitations of Reflection"。如果是default,您可以使用server_default

class User(db.Model):
    ...
    created_at = db.Column(db.DateTime,
                           server_default=text("now() at time zone 'UTC'"))

对于onupdate,您必须编写数据库触发器并使用server_onupdate=FetchedValue()

另一方面,您可以避免所有这些,只需将模型与应用程序代码分离到模块,Flask应用程序和脚本都使用该模块。这当然会涉及更多,因为您必须使用vanilla SQLAlchemy声明而不是Flask-SQLAlchemy的自定义db.Model基础。或者,您可以使用Flask的custom commands来实现脚本,这将允许使用Flask-SQLAlchemy扩展。