SQLAlchemyのデフォルトのDateTime


174

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

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

Base = declarative_base()

class Test(Base):
    __tablename__ = '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'

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


1
これは使用しないでください。utcnowはUTCタイムゾーンの単純なタイムスタンプですが、単純なタイムスタンプが代わりにローカルタイムゾーンで解釈される可能性があります。
Antti Haapala 2016年

1
私はこの質問がずっと前に尋ねられたことを知っていますが、あなたの答えは、@ Jeff Widmanが提供したものに変更する必要があると思います。もう1つは、テーブルクラスが定義されるときとレコードが作成されるときの「コンパイル」時間の日時を使用するためです。あなたがAFKである場合、少なくともこのコメントは、各質問のコメントを注意深くチェックするよう他の人に警告を提供します。
David

回答:


186

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

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

Base = declarative_base()

class Test(Base):
    __tablename__ = 'test'

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

13
これは正しくありません。モデルのロード時のタイムスタンプは、レコードが追加された時間ではなく、すべての新しいレコードに使用されます。
SkyLeach 2016

8
@SkyLeachこのコードは正しいです。ここでテストできます:pastebin.com/VLyWktUndatetime.datetime.utcnowコールバックと呼ばれるようです。
bux

1
この回答を使用しましたが、モデルのロード時のタイムスタンプがすべての新しいレコードに使用されています。
scottydelta 2017年

105
@scottdelta:を使用していないことを確認してくださいdefault=datetime.datetime.utcnow()utcnowモジュールのロード時に評価した結果ではなく、関数を渡したい。
機能不全

それでもうまくいきませんでした。jeff-widmanのアプローチは私にとってうまくいきました:from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()
tharndt

396

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

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

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

SQLALchemyの server_default

さらに、デフォルトで値を計算するようにDBに指示している場合は、通常、server_defaultではなくを使用することをお勧めします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に通知するだけで(おそらく列にトリガーを作成したため)、SQLAlchemyは戻り値を要求し、対応するオブジェクトを更新できるようにします。

もう1つの潜在的な問題:

単一のトランザクション内で一連の変更を行った場合、それらはすべて同じタイムスタンプを持つことに驚くかもしれません。これは、SQL標準で次のように指定されているためです。CURRENT_TIMESTAMPトランザクションの開始に基づいて値を返すようにです。

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

UTCタイムスタンプ

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


1
Postgresにトランザクションの開始時刻だけでなく、現在の時刻を使用するように指示する方法があることがわかりました...それはpostgresのドキュメントにあります
Jeff Widman

2
func.utcnow()またはそのようなものはありますか?
yerassyl 2017

1
@JeffWidman:utcnowのmysql実装はありますか?ドキュメンテーションでは、mssqlとpostregのみ
JavaSa

1
これは確かに素晴らしい答えです!
John Mutuma、2018

3
server_default=func.now()私のために働いたが、onupdate=func.now()しなかった。試したonupdate=datetime.datetime.utcnow(角括弧なし)、それも役に立たなかった
Vikas Prasad

55

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

from sqlalchemy.sql import func

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

9
値のserver_default代わりにdefaultデータベース自体で処理される値を使用することもできます。
rgtk 2015

2
記述子の定義時にfunc.now()は実行されないため、すべてのモデル/子(これが基本クラスの場合)は同じDT値を持ちます。「datetime.datetime.utcnow」のような関数参照を渡すことにより、それぞれ個別に実行されます。これは、「作成」または「更新」されたプロパティにとって重要です。
Metalstorm 2016

10
@Metalstormいいえ、これは正しいです。sqlalchemy.sql.funcは、現在の時刻ではなく、sqlalchemy.sql.functions.nowインスタンスを返す特殊なケースです。 docs.sqlalchemy.org/en/latest/core/...
クリスハーディ

何をしtimezone=Trueますか?
ChaimG 2016年

1
@self、ドキュメント「Trueの場合、バックエンドでサポートされている、 『TIMESTAMP WITH TIMEZONE』を生成しますタイムゾーンを意識タイムスタンプをサポートしていないバックエンドの場合は、効果がありません。。
ChaimG

7

onupdate=datetime.nowUPDATEもlast_updatedフィールドを変更するために使用する可能性があります。

SQLAlchemyには、Pythonで実行される関数のデフォルトが2つあります。

  • default INSERTの値を1回だけ設定します
  • onupdateUPDATE でも呼び出し可能な結果に値を設定します。

理由はわかりonupdateませんが、どういうわけか私には何もしません。
Vikas Prasad

1
:私は最終的にこれを行うことによって、PostgresのDBに取り組んでそれを得たcreated_at = db.Column(db.DateTime, server_default=UtcNow())updated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow())場所UtcNowとしてクラスがあるclass UtcNow(expression.FunctionElement): type = DateTime()と我々が持っている@compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
ヴィカスプラサド

6

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)

どこtime_nowから来たの?
はい-SEは悪です

ありがとうございました!その名前の組み込み関数がどういうわけか見落としていたと思いました。
わかりました-SEは悪です

またはdatetime.datetime.utcnow
serkef

1

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

now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.

これは機能と見なされます。1つのトランザクションが「現在の」時間の一貫した概念を持つことができるようにすることで、同じトランザクション内の複数の変更が同じタイムスタンプを持つようにします。

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

statement_timestamp()

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

clock_timestamp()

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

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.