Ini adalah model deklaratif saya:
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)
Namun, ketika saya mencoba mengimpor modul ini, saya mendapatkan kesalahan ini:
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'
Jika saya menggunakan tipe Integer, saya bisa menetapkan nilai default. Apa yang sedang terjadi?
python
date
sqlalchemy
Brandon O'Rourke
sumber
sumber
Jawaban:
DateTime
tidak memiliki kunci default sebagai input. Kunci default harus menjadi input keColumn
fungsi. Coba ini:sumber
datetime.datetime.utcnow
tampaknya disebut sebagai panggilan balik.default=datetime.datetime.utcnow()
; Anda ingin melewatkanutcnow
fungsi, bukan hasil mengevaluasinya pada beban modul.from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()
Hitung cap waktu dalam DB Anda, bukan klien Anda
Untuk kewarasan, Anda mungkin ingin semua
datetimes
dihitung oleh server DB Anda, bukan dari server aplikasi. Menghitung stempel waktu dalam aplikasi dapat menyebabkan masalah karena latensi jaringan bervariasi, klien mengalami pergeseran jam yang sedikit berbeda, dan bahasa pemrograman yang berbeda terkadang menghitung waktu sedikit berbeda.SQLAlchemy memungkinkan Anda untuk melakukan ini dengan melewati
func.now()
ataufunc.current_timestamp()
(mereka adalah alias satu sama lain) yang memberitahu DB untuk menghitung timestamp itu sendiri.Gunakan SQLALchemy
server_default
Selain itu, untuk default di mana Anda sudah memberi tahu DB untuk menghitung nilainya, umumnya lebih baik digunakan
server_default
daripadadefault
. Ini memberitahu SQLAlchemy untuk memberikan nilai default sebagai bagian dariCREATE TABLE
pernyataan.Misalnya, jika Anda menulis skrip ad hoc pada tabel ini, menggunakan
server_default
cara yang berarti Anda tidak perlu khawatir menambahkan panggilan timestamp secara manual ke skrip Anda - database akan mengaturnya secara otomatis.Memahami SQLAlchemy
onupdate
/server_onupdate
SQLAlchemy juga mendukung
onupdate
sehingga kapan pun baris diperbarui, akan menyisipkan stempel waktu baru. Sekali lagi, sebaiknya beri tahu DB untuk menghitung timestamp itu sendiri:Ada
server_onupdate
parameter, tetapi tidak sepertiserver_default
itu, itu tidak benar-benar mengatur apa pun sisi server. Ini hanya memberitahu SQLalchemy bahwa database Anda akan mengubah kolom ketika pembaruan terjadi (mungkin Anda membuat pemicu pada kolom ), jadi SQLAlchemy akan meminta nilai kembali sehingga dapat memperbarui objek yang sesuai.Satu potensi gotcha lainnya:
Anda mungkin terkejut melihat bahwa jika Anda membuat banyak perubahan dalam satu transaksi, mereka semua memiliki stempel waktu yang sama. Itu karena standar SQL menentukan bahwa
CURRENT_TIMESTAMP
mengembalikan nilai berdasarkan pada awal transaksi.PostgreSQL menyediakan non-SQL-standar
statement_timestamp()
danclock_timestamp()
yang melakukan perubahan dalam suatu transaksi. Documents di sini: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENTStempel waktu UTC
Jika Anda ingin menggunakan cap waktu UTC, potongan implementasi untuk
func.utcnow()
disediakan dalam dokumentasi SQLAlchemy . Anda perlu menyediakan fungsi spesifik driver yang sesuai sendiri.sumber
server_default=func.now()
bekerja untuk saya, tetapionupdate=func.now()
tidak. Mencobaonupdate=datetime.datetime.utcnow
(tanpa tanda kurung), itu juga tidak membantuAnda juga dapat menggunakan fungsi built-in sqlalchemy untuk default
DateTime
sumber
server_default
alih-alihdefault
nilai akan ditangani oleh basis data itu sendiri.timezone=True
harus dilakukanAnda mungkin ingin menggunakan
onupdate=datetime.now
sehingga UPDATE juga mengubahlast_updated
bidang.SQLAlchemy memiliki dua default untuk fungsi yang dieksekusi python.
default
menetapkan nilai pada INSERT, hanya sekalionupdate
menetapkan nilai ke hasil yang bisa dipanggil pada UPDATE juga.sumber
onupdate
tidak melakukan apa pun untuk saya.created_at = db.Column(db.DateTime, server_default=UtcNow())
dan diupdated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow())
manaUtcNow
kelasnya seperti yangclass UtcNow(expression.FunctionElement): type = DateTime()
kita miliki@compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
The
default
parameter kunci harus diberikan ke objek Kolom.Contoh:
Nilai standarnya bisa berupa callable, yang di sini saya definisikan seperti berikut.
sumber
time_now
?datetime.datetime.utcnow
Sesuai dokumentasi PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html
Anda mungkin ingin menggunakan statement_timestamp atau clock_timestamp jika Anda tidak ingin timestamp transaksi.
statement_timestamp ()
clock_timestamp ()
sumber