首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >SqlAlchemy时间戳'on update‘extra

SqlAlchemy时间戳'on update‘extra
EN

Stack Overflow用户
提问于 2015-11-17 03:46:54
回答 2查看 16K关注 0票数 7

我在python3.4.3上使用SqlAlchemy来管理一个MySQL数据库。我用以下命令创建了一个表:

代码语言:javascript
复制
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)

当我使用以下命令创建此表时:

代码语言:javascript
复制
engine = create_engine('{dialect}://{user}:{password}@{host}/{name}'.format(**utils.config['db']))
Base.metadata.create_all(engine)

我得到了:

代码语言:javascript
复制
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,尽管我看不出有任何理由会这样做。

我也尝试过:

代码语言:javascript
复制
created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=None, nullable=False)

代码语言:javascript
复制
created_at = Column(TIMESTAMP, default=datetime.utcnow, server_onupdate=text(''), nullable=False)

但问题依然存在。有什么建议吗?

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2015-11-17 04:56:57

显然,这个问题与SqlAlchemy无关,而是与底层的MySQL引擎有关。默认行为是在表中的第一个时间戳列上设置on update CURRENT_TIMESTAMP

这种行为在here中有描述。据我所知,一种可能的解决方案是使用--explicit_defaults_for_timestamp=FALSE标志启动MySQL。另一种解决方案是here。我还没有尝试过这两种解决方案,一旦我解决了问题,我就会更新这个答案。

编辑:我尝试了第二种方法,它不是很方便,但很有效。在我的例子中,我创建了一组没有created_at属性的表,然后按照上面的链接修改了所有剩余的表。

大致是这样的:

代码语言:javascript
复制
_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值:

代码语言:javascript
复制
created_at = Column(TIMESTAMP, default=datetime.utcnow, nullable=False, server_default=text('0'))
票数 7
EN

Stack Overflow用户

发布于 2019-11-28 12:23:26

我也遇到过同样的问题,你可以通过以下方法来实现:

代码语言:javascript
复制
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'))
票数 6
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/33743379

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档