SQLAlchemy默认DateTime

Bra*_*rke 140 python sqlalchemy date

这是我的声明模型:

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)
Run Code Online (Sandbox Code Playgroud)

但是,当我尝试导入此模块时,我收到此错误:

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'
Run Code Online (Sandbox Code Playgroud)

如果我使用Integer类型,我可以设置默认值.这是怎么回事?

Jef*_*man 309

计算数据库中的时间戳,而不是客户端

为了理智,您可能希望datetimes由数据库服务器而不是应用程序服务器计算所有数据.计算应用程序中的时间戳可能会导致问题,因为网络延迟是可变的,客户端遇到稍微不同的时钟漂移,而不同的编程语言偶尔会略微不同地计算时间.

SQLAlchemy允许您通过传递func.now()func.current_timestamp()(它们是彼此的别名)来执行此操作,这告诉DB计算时间戳本身.

使用SQLALchemy的 server_default

此外,对于您已经告诉数据库计算值的默认值,通常最好使用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())
Run Code Online (Sandbox Code Playgroud)

有一个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()提供了实现的存根.您需要自己提供适当的驱动程序特定功能.

  • `server_default=func.now()` 对我有用,但 `onupdate=func.now()` 没有。试过`onupdate=datetime.datetime.utcnow`(没有括号),这也没有帮助 (3认同)
  • 有没有func.utcnow()或类似的东西? (2认同)

Pea*_*oto 163

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)
Run Code Online (Sandbox Code Playgroud)

  • @scottdelta:确保你没有使用`default = datetime.datetime.utcnow()`; 你想传递`utcnow`函数,而不是在模块加载时评估它的结果. (84认同)
  • 这不对.模型加载的时间戳将用于所有新记录,而不是添加记录的时间. (8认同)
  • 我现在理解了这个线程中讨论的两种方法之间的区别:“server_default”将导致存储在 SQL 表定义级别的默认值(如果您在“psql”中执行“\d &lt;your_table&gt;”,则可以看到它实例),并且在 ORM 外部使用原始“插入”查询时会考虑到这一点。另一方面,“default”仅在 ORM 级别工作:如果您创建模型对象并保存它,它将包含默认值(因为 ORM 已显式设置它),而原始“insert”查询将导致没有默认值的记录。 (6认同)
  • 仍然不适合我。jeff-widman 的方法对我有用:`from sqlalchemy.sql import func; 创建日期=列(日期时间(时区= True),server_default = func.now()` (5认同)
  • @SkyLeach这段代码是正确的,你可以在这里测试一下:http://pastebin.com/VLyWktUn.``datetime.datetime.utcnow``似乎被称为回调. (4认同)
  • 我使用了这个答案,但模型加载时的时间戳用于所有新记录。 (4认同)

小智 51

您还可以使用sqlalchemy内置函数作为默认DateTime

from sqlalchemy.sql import func

DT = Column(DateTime(timezone=True), default=func.now())
Run Code Online (Sandbox Code Playgroud)

  • 您也可以使用`server_default`而不是`default`,因此值将由数据库本身处理. (7认同)
  • @Metalstorm不,这是对的.sqlalchemy.sql.func是一个特殊情况,它返回sqlalchemy.sql.functions.now实例,而不是当前时间.http://docs.sqlalchemy.org/en/latest/core/defaults.html#sql-expressions (7认同)
  • `timezone=True` 有什么作用? (4认同)
  • 定义描述符时不执行func.now(),因此所有模型/子项(如果这是基类)将具有相同的DT值.通过传入像'datetime.datetime.utcnow'这样的函数引用,它将分别为每个引用执行.这对"创建"或"更新"属性至关重要. (2认同)
  • @self,来自 [文档](http://docs.sqlalchemy.org/en/latest/core/type_basics.html):_"如果为 True,并由后端支持,将产生 'TIMESTAMP WITH TIMEZONE'。对于不支持时区感知时间戳的后端无效。_。 (2认同)

小智 15

使用default参数datetime.now

from sqlalchemy import Column, Integer, DateTime
from datetime import datetime
class Test(Base):
     __tablename__ = 'test'
     id = Column(Integer, primary_key=True)
     created_at = Column(DateTime, default=datetime.now)
     updated_at = Column(DateTime, default=datetime.now, onupdate=datetime.now)                                                            
Run Code Online (Sandbox Code Playgroud)

  • 请正确格式化您的代码,并可能解释一下它如何解决问题。 (4认同)

use*_*572 13

您可能希望使用,onupdate=datetime.now以便 UPDATE 也更改该last_updated字段。

SQLAlchemy 对 python 执行的函数有两个默认值。

  • default 在 INSERT 上设置值,仅一次
  • onupdate也将值设置为UPDATE上的可调用结果。

  • 我终于通过这样做在 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): 返回 "TIMEZONE('utc', CURRENT_TIMESTAMP)"` (4认同)
  • 我不知道为什么,但由于某种原因“onupdate”对我没有任何作用。 (2认同)

Kei*_*ith 5

default关键字参数应被给予Column对象.

例:

Column(u'timestamp', TIMESTAMP(timezone=True), primary_key=False, nullable=False, default=time_now),
Run Code Online (Sandbox Code Playgroud)

默认值可以是可调用的,这里我定义如下.

from pytz import timezone
from datetime import datetime

UTC = timezone('UTC')

def time_now():
    return datetime.now(UTC)
Run Code Online (Sandbox Code Playgroud)

  • 或 `datetime.datetime.utcnow` (3认同)