我在python3.4.3上使用SqlAlchemy来管理一个MySQL数据库。我用以下命令创建了一个表:
from datetime import datetime
from sqlalchemy import Column, text, create_engine
from sqlalchemy.types import TIMESTAMP
from sqlalchemy.dialects.mysql import BIGINT
from sqlalchemy.ext.declarative import declarative_base
Base = declarative_base()
class MyClass(Base):
__tablename__ = 'my_class'
id = Column(BIGINT(unsigned=True), primary_key=True)
created_at = Column(TIMESTAMP, default=datetime.utcnow, nullable=False)
updated_at = Column(TIMESTAMP, default=datetime.utcnow, onupdate=datetime.utcnow, nullable=False)
param1 = Column(BIGINT(unsigned=True), server_default=text('0'), nullable=False)当我使用以下命令创建此表时:
engine = create_engine('{dialect}://{user}:{password}@{host}/{name}'.format(**utils.config['db']))
Base.metadata.create_all(engine)我得到了:
mysql> describe my_class;
+----------------+---------------------+------+-----+---------------------+-----------------------------+
| Field | Type | Null | Key | Default | Extra |
+----------------+---------------------+------+-----+---------------------+-----------------------------+
| id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| created_at | timestamp | NO | | CURRENT_TIMESTAMP | on update CURRENT_TIMESTAMP | |
| updated_at | timestamp | NO | | 0000-00-00 00:00:00 | |
| param1 | bigint(20) unsigned | NO | | 0 | |现在的问题是,我不希望在我的created_at属性上有任何默认的on_update服务器,事实上,它的目的是只在创建记录时写入,而不是在类的声明中声明的每次更新时写入。
从我做过的几个测试中,我注意到如果我在created_at之前插入另一个TIMESTAMP类型的属性,那么这个属性会获得额外的on update CURRENT_TIMESTAMP,而created_at则不会。这表明SqlAlchemy在映射声明中找到的第一个TIMESTAMP属性会获得额外的on update CURRENT_TIMESTAMP,尽管我看不出有任何理由会这样做。
我也尝试过:
created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=None, nullable=False)和
created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=text(''), nullable=False)但问题依然存在。有什么建议吗?
发布于 2015-11-17 04:56:57
显然,这个问题与SqlAlchemy无关,而是与底层的MySQL引擎有关。默认行为是在表中的第一个时间戳列上设置on update CURRENT_TIMESTAMP。
这种行为在here中有描述。据我所知,一种可能的解决方案是使用--explicit_defaults_for_timestamp=FALSE标志启动MySQL。另一种解决方案是here。我还没有尝试过这两种解决方案,一旦我解决了问题,我就会更新这个答案。
编辑:我尝试了第二种方法,它不是很方便,但很有效。在我的例子中,我创建了一组没有created_at属性的表,然后按照上面的链接修改了所有剩余的表。
大致是这样的:
_no_alter = set(['tables', 'which', 'do not', 'have', 'a created_at', 'column'])
Base.metadata.create_all(engine)
for table in Base.metadata.tables.keys():
if table not in _no_alter:
engine.execute(text('ALTER TABLE {} MODIFY created_at TIMESTAMP NOT NULL DEFAULT 0'.format(table)))EDIT2:另一种(更简单的)方法是在SqlAlchemy中为列设置一个server_default值:
created_at = Column(TIMESTAMP, default=datetime.utcnow, nullable=False, server_default=text('0'))发布于 2019-11-28 12:23:26
我也遇到过同样的问题,你可以通过以下方法来实现:
created_time = Column(TIMESTAMP, nullable=False, server_default=func.now())
updated_time = Column(TIMESTAMP, nullable=False, server_default=text('CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP'))https://stackoverflow.com/questions/33743379
复制相似问题