Oto mój deklaratywny model:
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)
Jednak gdy próbuję zaimportować ten moduł, pojawia się ten błąd:
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'
Jeśli używam typu Integer, mogę ustawić wartość domyślną. Co się dzieje?
python
date
sqlalchemy
Brandon O'Rourke
źródło
źródło
Odpowiedzi:
DateTime
nie ma domyślnego klucza jako wejścia. Domyślny klucz powinien być wejściem doColumn
funkcji. Spróbuj tego:źródło
datetime.datetime.utcnow
wydaje się być nazywany oddzwonieniem.default=datetime.datetime.utcnow()
; chcesz przekazaćutcnow
funkcję, a nie wynik oceny jej podczas ładowania modułu.from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()
Obliczaj sygnatury czasowe w swojej bazie danych, a nie w swoim kliencie
Ze względów rozsądnych prawdopodobnie chcesz, aby wszystko zostało
datetimes
obliczone przez serwer bazy danych, a nie przez serwer aplikacji. Obliczanie znacznika czasu w aplikacji może prowadzić do problemów, ponieważ opóźnienie sieci jest zmienne, klienci doświadczają nieco innego przesunięcia zegara, a różne języki programowania czasami obliczają czas nieco inaczej.SQLAlchemy pozwala to zrobić, przekazując
func.now()
lubfunc.current_timestamp()
(są one wzajemnymi aliasami), co mówi DB, aby obliczył sam znacznik czasu.Użyj SQLALchemy's
server_default
Dodatkowo, w przypadku domyślnego, w którym już mówisz DB, aby obliczył wartość, generalnie lepiej jest użyć
server_default
zamiastdefault
. To mówi SQLAlchemy, aby przekazał wartość domyślną jako częśćCREATE TABLE
instrukcji.Na przykład, jeśli napiszesz skrypt ad hoc na tej tabeli, użycie
server_default
oznacza, że nie będziesz musiał martwić się o ręczne dodawanie wywołania znacznika czasu do skryptu - baza danych ustawi go automatycznie.Zrozumienie SQLAlchemy
onupdate
/server_onupdate
SQLAlchemy obsługuje również,
onupdate
dzięki czemu za każdym razem, gdy wiersz jest aktualizowany, wstawia nowy znacznik czasu. Ponownie, najlepiej powiedzieć DB, aby obliczył sam znacznik czasu:Jest
server_onupdate
parametr, ale w przeciwieństwie doserver_default
tego nie ustawia on niczego po stronie serwera. Po prostu mówi SQLalchemy, że twoja baza danych zmieni kolumnę, gdy nastąpi aktualizacja (być może utworzyłeś wyzwalacz w kolumnie ), więc SQLAlchemy zapyta o wartość zwracaną, aby mógł zaktualizować odpowiedni obiekt.Jeszcze jedna potencjalna wpadka:
Możesz być zaskoczony, gdy zauważysz, że jeśli dokonasz wielu zmian w ramach jednej transakcji, wszystkie mają ten sam znacznik czasu. Dzieje się tak, ponieważ standard SQL określa, że
CURRENT_TIMESTAMP
zwraca wartości na podstawie początku transakcji.PostgreSQL zapewnia non-SQL standard
statement_timestamp()
iclock_timestamp()
które zrobić zmiany w obrębie transakcji. Dokumenty tutaj: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENTZnacznik czasu UTC
Jeśli chcesz używać sygnatur czasowych UTC,
func.utcnow()
w dokumentacji SQLAlchemy znajduje się kod implementacji . Musisz jednak samodzielnie zapewnić odpowiednie funkcje specyficzne dla sterownika.źródło
server_default=func.now()
pracował dla mnie, aleonupdate=func.now()
nie. Próbowałemonupdate=datetime.datetime.utcnow
(bez nawiasów), to też nie pomogłoMożesz także użyć domyślnej funkcji wbudowanej sqlalchemy
DateTime
źródło
server_default
zamiast,default
więc wartość będzie obsługiwana przez samą bazę danych.timezone=True
?Prawdopodobnie będziesz chciał użyć
onupdate=datetime.now
, aby UPDATEs również zmieniałylast_updated
pole.SQLAlchemy ma dwie wartości domyślne dla funkcji wykonywanych w Pythonie.
default
ustawia wartość na INSERT, tylko razonupdate
ustawia wartość na wywoływalny wynik również w UPDATE.źródło
onupdate
nic dla mnie nie robi.created_at = db.Column(db.DateTime, server_default=UtcNow())
iupdated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow())
gdzieUtcNow
jest klasa jakclass UtcNow(expression.FunctionElement): type = DateTime()
i mamy@compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
default
Parametr Hasło powinno być podane do obiektu kolumnie.Przykład:
Wartość domyślna może być wywoływalna, co tutaj zdefiniowałem jak poniżej.
źródło
time_now
bierze?datetime.datetime.utcnow
Zgodnie z dokumentacją PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html
Jeśli nie chcesz, aby sygnatura czasowa transakcji była używana , możesz użyć parametru Statement_timestamp lub clock_timestamp .
Statement_timestamp ()
clock_timestamp ()
źródło