7

MySQL データベースを管理するために python3.4.3 で SqlAlchemy を使用しています。私はテーブルを作成していました:

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。実際、その目的は、クラスの宣言で述べられているように、すべての更新ではなく、レコードの作成時にのみ書き込まれることです。

私が行ったいくつかのテストから、 type の別の属性を の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)

しかし、問題は解決しません。なにか提案を?

4

2 に答える 2

7

どうやら問題は SqlAlchemy ではなく、基盤となる MySQL エンジンに関連しているようです。デフォルトの動作はon update CURRENT_TIMESTAMP、テーブルの最初の TIMESTAMP 列に設定することです。

この動作については、こちらで説明しています。私が理解している限り、考えられる解決策は、MySQL を--explicit_defaults_for_timestamp=FALSEフラグで起動することです。別の解決策はこちらにあります。どちらのソリューションもまだ試していません。問題が解決したらすぐにこの回答を更新します。

編集:2番目の方法を試しましたが、あまり便利ではありませんが、機能します。私の場合、属性を持たない一連のテーブルを作成し、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'))
于 2015-11-16T20:56:56.890 に答える