这是我的声明性模型:
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'
如果我使用Integer类型,我可以设置默认值。这是怎么呢
在数据库中计算时间戳,而不是在客户端中
为了合理起见,您可能希望所有日期时间都由您的DB服务器计算,而不是应用程序服务器。在应用程序中计算时间戳可能会导致问题,因为网络延迟是可变的,客户机的时钟漂移略有不同,不同的编程语言偶尔计算时间也略有不同。
SQLAlchemy允许您通过传递funct .now()或funct .current_timestamp()(它们是彼此的别名)来做到这一点,它们告诉DB计算时间戳本身。
使用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将请求返回值,以便更新相应的对象。
另一个潜在的问题是:
您可能会惊讶地发现,如果在单个事务中进行了大量更改,它们都具有相同的时间戳。这是因为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()的实现存根。不过,您需要自己提供适当的特定于驱动程序的函数。
默认的关键字参数应该给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)