Voici mon modèle déclaratif:
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)
Cependant, lorsque j'essaye 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?
python
date
sqlalchemy
Brandon O'Rourke
la source
la source
Réponses:
DateTime
n'a pas de clé par défaut comme entrée. La clé par défaut doit être une entrée de laColumn
fonction. Essaye ça:la source
datetime.datetime.utcnow
semble appelé comme rappel.default=datetime.datetime.utcnow()
; vous voulez passer lautcnow
fonction, pas le résultat de son évaluation au chargement du module.from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()
Calculez les horodatages dans votre base de données, pas dans votre client
Par souci de cohérence, vous souhaiterez probablement que tout soit
datetimes
calculé 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 entraîner 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 légèrement différemment.SQLAlchemy vous permet de le faire en passant
func.now()
oufunc.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 SQLALchemy
server_default
De plus, pour une valeur par défaut où vous dites déjà à la base de données de calculer la valeur, il est généralement préférable d'utiliser à la
server_default
place dedefault
. Cela indique à SQLAlchemy de transmettre la valeur par défaut dans le cadre de l'CREATE TABLE
instruction.Par exemple, si vous écrivez un script ad hoc sur cette table, l'utilisation
server_default
signifie que vous n'aurez pas à vous soucier de l'ajout manuel d'un appel d'horodatage à votre script - la base de données le définira automatiquement.Comprendre SQLAlchemy
onupdate
/server_onupdate
SQLAlchemy prend également en charge
onupdate
afin que chaque fois que la ligne est mise à jour, il insère un nouvel horodatage. Encore une fois, mieux vaut dire à la base de données de calculer l'horodatage lui-même:Il y a un
server_onupdate
paramètre, mais contrairement àserver_default
cela, il ne définit rien côté serveur. Il indique simplement à SQLalchemy que votre base de données changera la colonne lorsqu'une mise à jour se produit (peut-être avez-vous créé un déclencheur sur la colonne ), donc SQLAlchemy demandera la valeur de retour afin de pouvoir mettre à jour l'objet correspondant.Un autre gotcha potentiel:
Vous serez peut-être surpris de constater que si vous apportez un ensemble de modifications dans une seule transaction, elles ont toutes le même horodatage. C'est parce que la norme SQL spécifie que
CURRENT_TIMESTAMP
renvoie des valeurs basées sur le début de la transaction.PostgreSQL fournit la non-SQL standard
statement_timestamp()
etclock_timestamp()
qui ne le changement dans une transaction. Docs ici: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENTHorodatage UTC
Si vous souhaitez utiliser les horodatages UTC, un stub d'implémentation pour
func.utcnow()
est fourni dans la documentation SQLAlchemy . Vous devez cependant fournir vous-même les fonctions spécifiques au pilote.la source
server_default=func.now()
a travaillé pour moi, maisonupdate=func.now()
pas. Essayéonupdate=datetime.datetime.utcnow
(sans crochets), cela n'a pas non plus aidéVous pouvez également utiliser la fonction intégrée sqlalchemy par défaut
DateTime
la source
server_default
place dedefault
ce que la valeur sera gérée par la base de données elle-même.timezone=True
-on?Vous souhaiterez probablement utiliser
onupdate=datetime.now
pour que les MISES À JOUR modifient également lelast_updated
champ.SQLAlchemy a deux valeurs par défaut pour les fonctions exécutées en python.
default
définit la valeur sur INSERT, une seule foisonupdate
définit également la valeur du résultat appelable lors de UPDATE.la source
onupdate
ne fait rien pour moi.created_at = db.Column(db.DateTime, server_default=UtcNow())
etupdated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow())
oùUtcNow
est une classe commeclass UtcNow(expression.FunctionElement): type = DateTime()
et nous avons@compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
Le
default
paramètre de mot-clé doit être donné à l'objet Column.Exemple:
La valeur par défaut peut être un appelable, que j'ai défini ici comme suit.
la source
time_now
vient-il?datetime.datetime.utcnow
Selon la documentation PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html
Vous pouvez utiliser statement_timestamp ou clock_timestamp si vous ne voulez pas d'horodatage de transaction.
statement_timestamp ()
horloge_horodatage ()
la source