fecha y hora por defecto de SQLAlchemy

8 minutos de lectura

avatar de usuario
Brandon O´Rourke

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 Integer, puedo establecer un valor predeterminado. ¿Que esta pasando?

  • Esto no debe usarse. utcnow es una marca de tiempo ingenua en la zona horaria UTC, sin embargo, es probable que las marcas de tiempo ingenuas se interpreten en la zona horaria local.

    – Antti Haapala — Слава Україні

    6 de octubre de 2016 a las 7:33

  • Sé que esta pregunta se hizo hace mucho tiempo, pero creo que su respuesta debe cambiarse por la que proporcionó @Jeff Widman, ya que la otra usará la fecha y hora de “compilación” cuando se define la clase de tabla en lugar de cuando se crea el registro. Si está AFK, al menos este comentario proporcionará una advertencia para que otros revisen cuidadosamente los comentarios para cada pregunta.

    – David

    21 de febrero de 2019 a las 21:12

avatar de usuario
Jeff Widman

Calcule las marcas de tiempo dentro de su base de datos, no de su cliente

Por cordura, probablemente quiera tener todos datetimes calculado por su servidor DB, en lugar del servidor de aplicaciones. El cálculo de 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 forma 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 en sí.

Utilice SQLALchemy server_default

Además, para un valor predeterminado en el que ya le está diciendo a la base de datos que calcule el valor, generalmente es mejor usar server_default en vez de default. Esto le dice a SQLAlchemy que pase el valor predeterminado como parte del CREATE TABLE declaración.

Por ejemplo, si escribe un script ad hoc en esta tabla, utilizando server_default significa que no tendrá que preocuparse por agregar manualmente una llamada de marca de tiempo a su secuencia de comandos: la base de datos la configurará automáticamente.

Comprensión de SQLAlchemy onupdate/server_onupdate

SQLAlchemy también admite onupdate para que cada vez que se actualice la fila, inserte una nueva marca de tiempo. Nuevamente, es mejor decirle a la base de datos que calcule la marca de tiempo en sí:

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 server_default, en realidad no establece nada en el servidor. Simplemente le dice a SQLalchemy que su base de datos cambiará la columna cuando ocurra una actualización (tal vez creó un gatillo en la columna ), por lo que SQLAlchemy solicitará el valor devuelto para poder actualizar el objeto correspondiente.

Otro problema potencial:

Es posible que se sorprenda al notar que si realiza un montón de cambios en una sola transacción, todos tienen la misma marca de tiempo. Eso es porque 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() cual hacer cambiar 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, un trozo de implementación para func.utcnow() se proporciona en Documentación de SQLAlchemy. Sin embargo, debe proporcionar las funciones específicas del controlador adecuadas por su cuenta.

  • Estoy totalmente de acuerdo contigo. Sin embargo, mi configuración no funciona. “` clase TimestampMixin(objeto): created_at = Column(‘created_at’, DateTime(timezone=True), default=func.now()) updated_at = Column(‘updated_at’, DateTime(timezone=True), default=func .now(), onupdate=func.now()) “` Emití una declaración de creación y actualización con 1 segundo de diferencia. Los dos valores para created_at y updated_at son siempre los mismos.

    – Khanh Hua

    8 de enero de 2016 a las 2:16


  • Vi que ahora hay una manera de decirle a Postgres que use la hora actual, no solo la hora de inicio de la transacción… está en los documentos de Postgres

    –Jeff Widman

    5 mayo 2016 a las 22:03

  • ¿Hay un func.utcnow() o algo así?

    – yerassyl

    19 de abril de 2017 a las 4:47

  • @JeffWidman: ¿Tenemos una implementación de mysql para utcnow? Yo en documentación solo mssql y postreg

    – Java Sa

    29 de noviembre de 2017 a las 15:13


  • server_default=func.now() funcionó para mí, pero onupdate=func.now() no. Intentó onupdate=datetime.datetime.utcnow (sin paréntesis), eso tampoco ayudó

    – Vikas Prasad

    16 de agosto de 2018 a las 15:03


avatar de usuario
PearsonArteFoto

DateTime no tiene una clave predeterminada como entrada. La clave predeterminada debe ser una entrada para el 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)

  • Esto no está bien. La marca de tiempo en la carga del modelo se utilizará para todos los registros nuevos en lugar de la hora en que se agrega el registro.

    – SkyLeach

    9 de febrero de 2016 a las 16:18

  • @SkyLeach Este código es correcto, puedes probarlo aquí: pastebin.com/VLyWktUn . datetime.datetime.utcnow parece llamado como devolución de llamada.

    – bux

    04/03/2016 a las 14:55

  • Usé esta respuesta, pero la marca de tiempo en la carga del modelo se usa para todos los registros nuevos.

    – scottydelta

    26 de enero de 2017 a las 2:20

  • @scottdelta: asegúrese de no estar usando default=datetime.datetime.utcnow(); quieres pasar el utcnow función, no el resultado de evaluarlo en la carga del módulo.

    – disfunción

    22 de febrero de 2017 a las 15:54


  • Todavía no funcionó para mí. El enfoque de jeff-widman funcionó para mí: from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()

    – gracias

    21 de enero de 2020 a las 10:18

avatar de usuario
QWERTY

También puede usar la función incorporada sqlalchemy por defecto DateTime

from sqlalchemy.sql import func

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

  • También puedes usar server_default en vez de default por lo tanto, el valor será manejado por la propia base de datos.

    – rgtk

    6 de junio de 2015 a las 14:55

  • No se ejecuta func.now() cuando se define el descriptor, por lo que todos los modelos/hijos (si se trata de una clase base) tendrán el mismo valor de DT. Al pasar una referencia de función como ‘datetime.datetime.utcnow’, se ejecuta por separado para cada uno. Esto es crucial para las propiedades ‘creadas’ o ‘actualizadas’.

    – Tormenta de metal

    26 de febrero de 2016 a las 1:27


  • @Metalstorm No, esto es correcto. sqlalchemy.sql.func es un caso especial que devuelve una instancia de sqlalchemy.sql.functions.now, no la hora actual. docs.sqlalchemy.org/en/latest/core/…

    – Kris Hardy

    15/03/2016 a las 22:25

  • Que hace timezone=True ¿hacer?

    – ChaimG

    23 de junio de 2016 a las 1:41

  • @self, Desde la documentación: “Si es Verdadero, y es compatible con el backend, producirá ‘TIMESTAMP WITH TIMEZONE’. Para los backends que no admiten marcas de tiempo conscientes de la zona horaria, no tiene efecto. .

    – ChaimG

    23 de junio de 2016 a las 1:45


avatar de usuario
usuario3389572

Es probable que desee utilizar onupdate=datetime.now para que las ACTUALIZACIONES también cambien el last_updated campo.

SQLAlchemy tiene dos valores predeterminados para las funciones ejecutadas de Python.

  • default establece el valor en INSERT, solo una vez
  • onupdate establece el valor de la invocable resultado en ACTUALIZAR también.

avatar de usuario
Raúl Mishra

Utilizando el default parámetro con 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)                                                            

  • Formatee su código correctamente y puede explicar un poco cómo resuelve el problema.

    – swag2198

    7 de mayo de 2021 a las 6:32

  • default=datetime.now en la columna, ahorrará tiempo al insertar los registros.

    – Raúl Mishra

    hace 2 días

los default El parámetro de palabra clave se debe dar al objeto de columna.

Ejemplo:

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

El valor predeterminado puede ser invocable, que aquí definí de la siguiente manera.

from pytz import timezone
from datetime import datetime

UTC = timezone('UTC')

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

  • Formatee su código correctamente y puede explicar un poco cómo resuelve el problema.

    – swag2198

    7 de mayo de 2021 a las 6:32

  • default=datetime.now en la columna, ahorrará tiempo al insertar los registros.

    – Raúl Mishra

    hace 2 días

avatar de usuario
maicon mauricio

según Documentación de PostgreSQL:

now, CURRENT_TIMESTAMP, LOCALTIMESTAMP devolver la hora de la transacción

Esto se considera una característica: la intención es permitir que una sola transacción tenga una noción consistente de la hora “actual”, de modo que múltiples modificaciones dentro de la misma transacción lleven la misma marca de tiempo.

Es posible que desee utilizar statement_timestamp o clock_timestamp si no desea la marca de tiempo de la transacción.

statement_timestamp()

devuelve la hora de inicio de la declaración actual (más específicamente, la hora de recepción del último mensaje de comando del cliente). declaración_marca de tiempo

clock_timestamp()

devuelve la hora actual real y, por lo tanto, su valor cambia incluso dentro de un solo comando SQL.

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad