SQLAlchemy DateTime default

Questo è il mio modello dichiarativo:

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)

Tuttavia, quando si tenta di importare questo modulo, ottengo questo errore:

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'

Se io uso un tipo Intero, posso impostare un valore di default. Che cosa sta succedendo?

  • Questo non dovrebbe essere utilizzato. utcnow è un ingenuo indicatore data e ora nel fuso orario UTC, tuttavia, le probabilità sono che ingenuo timestamp vengono interpretati nel fuso orario locale invece.
  • So che questa domanda è stata fatta molto tempo fa, ma penso che la tua risposta dovrebbe essere cambiato a quello che @Jeff Widman forniti come l’altra per l’utilizzo di “compilare” time datetime quando la tabella classe è definita rispetto a quando il record viene creato. Se sei AFK quindi almeno questo commento fornirà un avvertimento per gli altri a controllare attentamente i commenti per ogni domanda.



6 Replies
  1. 163

    DateTime non dispone di un tasto predefinito come input. La chiave di default dovrebbe essere un input per la Column funzione. Prova questo:

    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)
    • Questo non è giusto. Il timestamp al modello di carico dovrà essere utilizzato per tutti i nuovi record, piuttosto che il tempo, il record viene aggiunto.
    • Questo codice è corretto, è possibile verificare qui: pastebin.com/VLyWktUn . datetime.datetime.utcnow sembra chiamato come richiamata.
    • Ho usato questa risposta, ma il timestamp al modello di carico vengono utilizzati per tutti i nuovi record.
    • Assicurarsi che non si utilizza default=datetime.datetime.utcnow(); si desidera passare la utcnow funzione, non il risultato della valutazione al caricamento del modulo.
  2. 310

    Calcolare timestamp interno del tuo DB, non è il tuo client

    Per la sanità mentale, probabilmente si desidera avere tutti datetimes calcolata da DB server, piuttosto che l’applicazione server. Calcolare il timestamp applicazione possono portare a problemi in quanto la latenza di rete è variabile, clienti esperienza leggermente diversa clock drift, e diversi linguaggi di programmazione, occasionalmente, calcolare il tempo in modo leggermente diverso.

    SQLAlchemy permette di farlo passando func.now() o func.current_timestamp() (sono alias di ogni altro) che racconta il DB per calcolare l’indicatore di data e ora.

    Utilizzare SQLALchemy del server_default

    Inoltre, per impostazione predefinita, dove si sta già raccontando il DB per calcolare il valore, in genere è meglio usare server_default invece di default. Questo dice SQLAlchemy per passare il valore di default come parte del CREATE TABLE istruzione.

    Per esempio, se si scrive uno script ad hoc contro questa tabella, utilizzando server_default significa che non sarà necessario preoccuparsi di aggiungere manualmente un timestamp chiamare il tuo script–il database verrà impostato automaticamente.

    Comprensione SQLAlchemy del onupdate/server_onupdate

    SQLAlchemy supporta anche onupdate in modo che in qualsiasi momento la riga viene aggiornata inserisce un nuovo timestamp. Di nuovo, meglio dire il DB per calcolare l’indicatore di data e ora:

    from sqlalchemy.sql import func
    
    time_created = Column(DateTime(timezone=True), server_default=func.now())
    time_updated = Column(DateTime(timezone=True), onupdate=func.now())

    C’è un server_onupdate parametro, ma a differenza di server_default, in realtà, non impostare nulla serverside. Ci dice solo SQLalchemy che il tuo database di cambiare la colonna quando un aggiornamento accade (forse si è creato un trigger sulla colonna ), così SQLAlchemy chiederà il valore di ritorno è possibile aggiornare l’oggetto corrispondente.

    Un altro potenziale gotcha:

    Si potrebbe essere sorpresi di notare che se si fa un sacco di cambiamenti all’interno di una singola transazione, hanno tutti lo stesso indicatore. Questo perché l’SQL standard specifica che CURRENT_TIMESTAMP restituisce i valori in base all’inizio della transazione.

    PostgreSQL fornisce il non-SQL standard statement_timestamp() e clock_timestamp() che fare cambiamento all’interno di una transazione. Documentazione qui: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT

    Timestamp UTC

    Se si desidera utilizzare un timestamp UTC, uno stub di attuazione per func.utcnow() è fornito in SQLAlchemy documentazione. È necessario fornire le opportune funzioni specifiche del driver sul proprio però.

    • Sono totalmente d’accordo con te. Tuttavia, il mio setup non funziona. ` classe TimestampMixin(oggetto): created_at = Colonna(‘created_at’, data e ora(fuso orario=True), default=func.now()) updated_at = Colonna(‘updated_at’, data e ora(fuso orario=True), default=func.now(), onupdate=func.now()) “ ho rilasciato un creare e un’istruzione update 1 secondo di distanza. I due valori per created_at e updated_at sono sempre gli stessi.
    • IIRC, in PostgreSQL, se si problema sia di loro all’interno dello stesso DB transazione il timestamp vengono entrambi dall’inizio della transazione di tempo. Non sono sicuro su altri DB. Si può, inoltre, non sono scaricate e/o commesso il SQLAlchemy sessione tra il creare/aggiornare istruzione. Se non è nessuno di quelli, allora sarà molto più facile per eseguire il debug se si apre una nuova questione. Sentitevi liberi di includere un link qui e darò un’occhiata.
    • Ho avuto modo di vedere c’è un modo per dire a Postgres per utilizzare l’ora corrente, non appena la transazione iniziale tempo… è in postgres docs
    • c’è un func.utcnow() o qualcosa di simile?
    • Abbiamo un mysql attuazione per utcnow? Io nella documentazione solo mssql e postreg
    • Non so di sconto superiore della mia testa. Se si apre una nuova domanda e link ad esso qui poi posso provare a guardare in su.
    • Sei il benvenuto, stackoverflow.com/questions/47554658/…
    • Ha sqlalchemy.exc.OperationalError: (_mysql_exceptions.OperationalError) (1067, "Invalid default value for 'created'")
    • come impostare di default datetime fissa del datetime come 1970-1-1?
    • Questo, infatti, è una grande risposta!
    • server_default=func.now() ha funzionato per me, ma onupdate=func.now() non. Provato onupdate=datetime.datetime.utcnow (senza parentesi quadre), che non ha ancora aiutare
    • provato server_onupdate=func.now() troppo. Che non ha funzionato neanche.
    • Ho finalmente capito di lavoro a Postgres db in questo modo: created_at = db.Column(db.DateTime, server_default=UtcNow()) e updated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow()) dove UtcNow è una classe come class UtcNow(expression.FunctionElement): type = DateTime() e abbiamo @compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
    • Non credo che il onupdate genererà la definizione di colonna si prevede, nel senso che, non aggiornare il timestamp record di ‘aggiornamento’. Avete bisogno di un DB funzione + trigger update per fare questo.
    • grande risposta – cosa nota, almeno per me – inserisci ts iniziato a lavorare dopo ho ri-creato la tabella. invece di ri-creare la tabella è anche possibile modificare la tabella in mysql, e l’aggiunta di un’espressione (ultima colonna) dicendo CURRENT_TIMESTAMP
    • chiunque sa), assumendo di impostare la prima trigger update correttamente, non importa ciò che si mette in server_onupdate quindi se è solo un segnale di SQLAlchemy per tirare il nuovo valore dal DB?

  3. 51

    È inoltre possibile utilizzare sqlalchemy funzione builtin per default DateTime

    from sqlalchemy.sql import func
    
    DT = Column(DateTime(timezone=True), default=func.now())
    • È inoltre possibile utilizzare server_default invece di default in modo che il valore sarà gestita dal database stesso.
    • Non è func.now() viene eseguito quando il descrittore è definito, in modo che tutti i modelli/bambini (se questa è una classe base) avrà lo stesso valore di distacco. Passando un riferimento a una funzione come ‘datetime.datetime.utcnow’ viene eseguita separatamente per ogni. Questo è fondamentale per la ‘creazione’ o ‘aggiornato’ proprietà.
    • No, questo è corretto. sqlalchemy.sql.func è un caso speciale che restituisce un sqlalchemy.sql.funzioni.ora istanza, non l’ora corrente. docs.sqlalchemy.org/en/latest/core/…
    • Cosa timezone=True fare?
    • Da documentazione: “Se è Vero, e supportato dal back-end, di produrre ‘TIMESTAMP CON FUSO’. Per i sistemi che non supportano il fuso orario consapevoli timestamp, non ha alcun effetto. .
  4. 5

    Il default parola chiave parametro dovrebbe essere data alla Colonna oggetto.

    Esempio:

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

    Il valore di default può essere un callable, che qui ho definito come il seguente.

    from pytz import timezone
    from datetime import datetime
    
    UTC = timezone('UTC')
    
    def time_now():
        return datetime.now(UTC)
    • Da dove viene time_now provengono da?
    • Grazie! Ho dato per scontato che c’è un built-in funzione con quel nome che in qualche modo trascurato.
    • o datetime.datetime.utcnow
  5. 4

    È probabile che si desidera utilizzare onupdate=datetime.now in modo che gli Aggiornamenti anche cambiare il last_updated campo.

    SQLAlchemy ha due valori di default per python eseguito funzioni.

    • default imposta il valore su INSERISCI, solo una volta
    • onupdate imposta il valore per il callable risultato in AGGIORNAMENTO.
    • Non so perché, ma per qualche motivo onupdate non fa nulla per me.
    • Ho finalmente capito di lavoro a Postgres db in questo modo: created_at = db.Column(db.DateTime, server_default=UtcNow()) e updated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow()) dove UtcNow è una classe come class UtcNow(expression.FunctionElement): type = DateTime() e abbiamo @compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
  6. 1

    Come per la documentazione di PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html

    now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.

    Questa è considerata una caratteristica: l’intento è quello di consentire a un singolo
    transazione di avere una costante nozione di “corrente”, di modo che
    modifiche multiple all’interno della stessa transazione orso stesso tempo
    stamp.

    Si potrebbe desiderare di utilizzare statement_timestamp o clock_timestamp se non vuoi transazione timestamp.

    statement_timestamp()

    restituisce l’ora di inizio dell’istruzione corrente (più specificamente,
    il tempo di consegna del messaggio di comando dal client).
    statement_timestamp

    clock_timestamp()

    restituisce l’effettiva corrente di tempo, e quindi il suo valore cambia anche
    all’interno di un singolo comando SQL.

Lascia un commento