2015-11-16 2 views
1

Я использую SqlAlchemy на python3.4.3 для управления базой данных MySQL. Я создавал таблицу:SqlAlchemy TIMESTAMP 'on update' extra

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 сервера default по моему атрибуту created_at, его назначение, по сути, написано только при создании записи, а не на каждом обновлении, как указано в объявлении класса.

Из нескольких тестов я сделал, я заметил, что если я ввожу еще один атрибут типа TIMESTAMP перед тем created_at, то этот атрибут получает on update CURRENT_TIMESTAMP дополнительные, в то время как created_at делает не так, как хотелось бы. Это говорит о том, что первый атрибут TIMESTAMP SqlAlchemy, который находит в объявлении отображения, получает дополнительно 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. По умолчанию задано значение on update CURRENT_TIMESTAMP в первом столбце TIMESTAMP в таблице.

Данное поведение описано here. Насколько я понимаю, возможным решением является запуск MySQL с флагом --explicit_defaults_for_timestamp=FALSE. Другое решение можно найти here. Я еще не пробовал ни одного решения, я обновлю этот ответ, как только решит проблему.

EDIT: Я попробовал второй метод, и это не очень удобно, но оно работает. В моем случае я создал набор таблиц, которые не имеют атрибута 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')) 
Смежные вопросы