web-dev-qa-db-ja.com

SQLAlchemyのデフォルトのDateTime

これは私の宣言モデルです:

import datetime
from sqlalchemy import Column, Integer, DateTime
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Test(Base):
    __table= 'test'

    id = Column(Integer, primary_key=True)
    created_date = DateTime(default=datetime.datetime.utcnow)

ただし、このモジュールをインポートしようとすると、次のエラーが表示されます。

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "orm/models2.py", line 37, in <module>
    class Test(Base):
  File "orm/models2.py", line 41, in Test
    created_date = sqlalchemy.DateTime(default=datetime.datetime.utcnow)
TypeError: __init__() got an unexpected keyword argument 'default'

整数型を使用する場合、デフォルト値を設定できます。どうしたの?

115

DateTimeには、入力としてデフォルトキーがありません。デフォルトのキーは、Column関数への入力でなければなりません。これを試して:

import datetime
from sqlalchemy import Column, Integer, DateTime
from sqlalchemy.ext.declarative import declarative_base

Base = declarative_base()

class Test(Base):
    __table= 'test'

    id = Column(Integer, primary_key=True)
    created_date = Column(DateTime, default=datetime.datetime.utcnow)
147
PearsonArtPhoto

クライアントではなく、DB内のタイムスタンプを計算します

正気のために、おそらくすべてのdatetimesを、アプリケーションサーバーではなく、DBサーバーによって計算する必要があります。アプリケーションでタイムスタンプを計算すると、ネットワークレイテンシが変化し、クライアントで発生するクロックドリフトがわずかに異なり、プログラミング言語によって時間の計算が少し異なるため、問題が発生する可能性があります。

SQLAlchemyでは、 func.now() または func.current_timestamp() (これらは互いにエイリアスである)を渡すことでこれを行うことができます。タイムスタンプ自体を計算するDB。

SQLALchemyのserver_defaultを使用

さらに、既に値を計算するようにDBに指示しているデフォルトの場合は、通常、defaultの代わりに server_default を使用することをお勧めします。これにより、SQLAlchemyはCREATE TABLEステートメントの一部としてデフォルト値を渡すようになります。

たとえば、このテーブルに対してアドホックスクリプトを記述する場合、server_defaultを使用すると、手動でスクリプトにタイムスタンプコールを追加する必要がなくなります。データベースによって自動的に設定されます。

SQLAlchemyのonupdate/server_onupdateを理解する

SQLAlchemyはonupdateもサポートしているため、行が更新されるたびに新しいタイムスタンプが挿入されます。繰り返しますが、タイムスタンプ自体を計算するようにDBに指示するのが最善です。

from sqlalchemy.sql import func

time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())

server_onupdate パラメーターがありますが、server_defaultとは異なり、実際にはサーバーサイドには何も設定されません。更新が発生するとデータベースが列を変更することをSQLalchemyに伝えるだけです(おそらく、列に triggerを作成した/ )。したがって、SQLAlchemyは戻り値を要求します対応するオブジェクトを更新できます。

もう1つの潜在的な落とし穴:

驚いたかもしれませんが、1つのトランザクション内で多数の変更を加えた場合、それらはすべて同じタイムスタンプを持ちます。これは、SQL標準がCURRENT_TIMESTAMPがトランザクションの開始に基づいて値を返すことを指定しているためです。

PostgreSQLは、トランザクション内でdoを変更する非SQL標準のstatement_timestamp()およびclock_timestamp()を提供します。ここのドキュメント: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT

UTCタイムスタンプ

UTCタイムスタンプを使用する場合は、func.utcnow()の実装のスタブが SQLAlchemy documentation で提供されます。ただし、適切なドライバ固有の機能を自分で提供する必要があります。

266
Jeff Widman

デフォルトのDateTimeにsqlalchemy組み込み関数を使用することもできます

from sqlalchemy.sql import func

DT = Column(DateTime(timezone=True), default=func.now())
46
qwerty

defaultキーワードパラメータをColumnオブジェクトに指定する必要があります。

例:

Column(u'timestamp', TIMESTAMP(timezone=True), primary_key=False, nullable=False, default=time_now),

デフォルト値は呼び出し可能にすることができ、ここでは次のように定義します。

from pytz import timezone
from datetime import datetime

UTC = timezone('UTC')

def time_now():
    return datetime.now(UTC)
5
Keith

[ここにリンクの説明を入力してください] [1]

おそらくonupdate = datetime.nowを使用して、UPDATEがlast_updatedフィールドも変更するようにします。

[1]:SQLAlchemyには、python実行関数の2つのデフォルトがあります。

  • デフォルト INSERTの値を1回だけ設定します
  • onupdateは、UPDATEの結果もcallable結果に設定します。
4
user3389572

PostgreSQLのドキュメントによると、 https://www.postgresql.org/docs/9.6/static/functions-datetime.html

now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.

これは機能と見なされます。その目的は、単一のトランザクションに「現在の」時間の一貫した概念を持たせ、同じトランザクション内の複数の変更に同じタイムスタンプを付けることです。

使用したくない場合は、statement_timestampまたはclock_timestampを使用できますトランザクションのタイムスタンプ。

statement_timestamp()

現在のステートメントの開始時間(より具体的には、クライアントからの最新のコマンドメッセージの受信時間)を返します。 statement_timestamp

clock_timestamp()

実際の現在時刻を返すため、その値は単一のSQLコマンド内でも変化します。

1
abhi shukla