Fecha y hora predeterminada de SQLAlchemy
Este es mi modelo declarativo:
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)
Sin embargo, cuando intento importar este módulo, aparece este error:
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'
Si uso un tipo Entero, puedo establecer un valor predeterminado. ¿Qué está sucediendo?
Calcule marcas de tiempo dentro de su base de datos, no de su cliente
Por razones de cordura, probablemente desee datetimes
que su servidor de base de datos calcule todo, en lugar del servidor de aplicaciones. Calcular la marca de tiempo en la aplicación puede generar problemas porque la latencia de la red es variable, los clientes experimentan una desviación del reloj ligeramente diferente y, en ocasiones, diferentes lenguajes de programación calculan el tiempo de manera ligeramente diferente.
SQLAlchemy le permite hacer esto pasando func.now()
o func.current_timestamp()
(son alias entre sí) que le dice a la base de datos que calcule la marca de tiempo.
Utilice SQLALchemyserver_default
Además, para un valor predeterminado en el que ya le está indicando a la base de datos que calcule el valor, generalmente es mejor usarlo server_default
en lugar de default
. Esto le dice a SQLAlchemy que pase el valor predeterminado como parte de la CREATE TABLE
declaración.
Por ejemplo, si escribe un script ad hoc en esta tabla, usar server_default
significa que no tendrá que preocuparse por agregar manualmente una llamada de marca de tiempo a su script: la base de datos la configurará automáticamente.
Entendiendo SQLAlchemy onupdate
/server_onupdate
SQLAlchemy también admite onupdate
que cada vez que se actualice la fila se inserte una nueva marca de tiempo. Nuevamente, es mejor decirle a la base de datos que calcule la marca de tiempo:
from sqlalchemy.sql import func
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
Hay un server_onupdate
parámetro, pero a diferencia de server_default
, en realidad no establece nada en el lado del servidor. Simplemente le dice a SQLalchemy que su base de datos cambiará la columna cuando ocurra una actualización (tal vez creó un disparador en la columna ), por lo que SQLAlchemy le pedirá el valor de retorno para poder actualizar el objeto correspondiente.
Otro problema potencial:
Te sorprenderá notar que si realizas muchos cambios en una sola transacción, todos tendrán la misma marca de tiempo. Esto se debe a que el estándar SQL especifica que CURRENT_TIMESTAMP
devuelve valores basados en el inicio de la transacción.
PostgreSQL proporciona el estándar no SQL statement_timestamp()
y clock_timestamp()
cuáles cambian dentro de una transacción. Documentos aquí: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
marca de tiempo UTC
Si desea utilizar marcas de tiempo UTC, func.utcnow()
se proporciona un fragmento de implementación en la documentación de SQLAlchemy . Sin embargo, debe proporcionar usted mismo las funciones específicas del controlador adecuadas.
DateTime
no tiene una clave predeterminada como entrada. La clave predeterminada debe ser una entrada a la Column
función. Prueba esto:
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)
También puede usar la función incorporada sqlalchemy por defectoDateTime
from sqlalchemy.sql import func
DT = Column(DateTime(timezone=True), default=func.now())