2015-11-16 50 views
1

我在python3.4.3上使用SqlAlchemy來管理MySQL數據庫。我創建一個表:SqlAlchemy TIMESTAMP'on update'額外

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     |        | 

現在的問題是,我不希望有任何on_update服務器在我的created_at屬性上是默認的,它的目的實際上只是在創建記錄時才寫的,而不是在每次更新時寫的,正如課程的聲明中所述。

從幾個測試我做了,我發現,如果我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) 

,但問題仍然存在。 有什麼建議嗎?

回答

1

顯然這個問題與SqlAlchemy無關,但與底層MySQL引擎有關。默認行爲是在表中的第一個TIMESTAMP列上設置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'))