web-dev-qa-db-fra.com

SQLAlchemy par défaut DateTime

Ceci est mon modèle déclaratif:

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

Base = declarative_base()

class Test(Base):
    __table= 'test'

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

Cependant, lorsque j'essaie d'importer ce module, j'obtiens cette erreur:

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 j'utilise un type Integer, je peux définir une valeur par défaut. Que se passe-t-il?

98
Brandon O'Rourke

DateTime n'a pas de clé par défaut en entrée. La clé par défaut doit être une entrée de la fonction Column. Essaye ça:

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

Base = declarative_base()

class Test(Base):
    __table= 'test'

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

Calculez les horodatages dans votre base de données, pas votre client

Pour des raisons de sécurité, vous souhaitez probablement que toutes les variables datetimes soient calculées par votre serveur de base de données, plutôt que par le serveur d'applications. Le calcul de l'horodatage dans l'application peut poser des problèmes car la latence du réseau est variable, les clients subissent une dérive d'horloge légèrement différente et différents langages de programmation calculent parfois l'heure de manière légèrement différente. 

SQLAlchemy vous permet de le faire en transmettant func.now() ou func.current_timestamp() (ce sont des alias les uns des autres) qui indique à la base de données de calculer l'horodatage lui-même.

Utilisez le server_default de SQLALchemy

De plus, si vous indiquez déjà au DB de calculer la valeur par défaut, il est généralement préférable d'utiliser server_default au lieu de default. Cela indique à SQLAlchemy de transmettre la valeur par défaut dans le cadre de l'instruction CREATE TABLE.

Par exemple, si vous écrivez un script ad hoc sur cette table, l'utilisation de server_default signifie que vous n'aurez pas à vous inquiéter de l'ajout manuel d'un appel d'horodatage à votre script: la base de données le définira automatiquement.

Comprendre la variable onupdateserver_onupdate de SQLAlchemy

SQLAlchemy prend également en charge onupdate afin qu'à chaque fois que la ligne est mise à jour, elle insère un nouvel horodatage. Encore une fois, mieux vaut demander à la base de données de calculer l’horodatage lui-même: 

from sqlalchemy.sql import func

time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())

Il existe un paramètre server_onupdate , mais contrairement à server_default, il ne définit en réalité rien du côté serveur. Cela indique simplement à SQLalchemy que votre base de données modifiera la colonne lorsqu'une mise à jour aura lieu (vous avez peut-être créé un déclencheur sur la colonne ), de sorte que SQLAlchemy demandera la valeur de retour afin de pouvoir mettre à jour l'objet correspondant. 

Un autre potentiel de Gotcha:

Vous serez peut-être surpris de constater que, si vous apportez un grand nombre de modifications au sein d'une même transaction, elles ont toutes le même horodatage. En effet, le standard SQL spécifie que CURRENT_TIMESTAMP renvoie des valeurs en fonction du début de la transaction. 

PostgreSQL fournit les fonctions statement_timestamp() et clock_timestamp() non standard SQL que _/do modifient au sein d'une transaction. Docs here: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT

Horodatage UTC

Si vous souhaitez utiliser les horodatages UTC, un bloc d'implémentation pour func.utcnow() est fourni dans Documentation SQLAlchemy . Vous devez cependant fournir vous-même les fonctions appropriées spécifiques au pilote.

234
Jeff Widman

Vous pouvez également utiliser la fonction intégrée sqlalchemy pour DateTime par défaut

from sqlalchemy.sql import func

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

Le paramètre de mot clé default doit être attribué à l'objet Column.

Exemple:

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

La valeur par défaut peut être un appelable, ce que j'ai défini ici comme suit.

from pytz import timezone
from datetime import datetime

UTC = timezone('UTC')

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

[entrez la description du lien ici] [1]

Vous voudrez probablement utiliser onupdate = datetime.now pour que UPDATE modifie également le champ last_updated .

[1]: SQLAlchemy a deux valeurs par défaut pour les fonctions exécutées par python.

  • default définit la valeur sur INSERT, une seule fois
  • onupdate définit également la valeur sur le résultat callable sur UPDATE.
4
user3389572

Selon la documentation de PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html

now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.

Ceci est considéré comme une caractéristique: le but est d'autoriser un seul transaction d'avoir une notion cohérente de l'heure "actuelle", de sorte que plusieurs modifications dans la même transaction portent le même temps timbre.

Vous voudrez peut-être utiliser statement_timestamp ou clock_timestamp si vous ne voulez pas d'horodatage de transaction. 

statement_timestamp () 

renvoie l'heure de début de l'instruction en cours (plus précisément, l'heure de réception du dernier message de commande du client) . statement_timestamp

clock_timestamp () 

renvoie l'heure actuelle et, par conséquent, sa valeur change même au sein d'une seule commande SQL.

0
abhi shukla