SQLAlchemy varsayılan DateTime


174

Bu benim beyan modelim:

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)

Ancak, bu modülü almaya çalıştığınızda, bu hatayı alıyorum:

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'

Bir Tamsayı türü kullanırsam, varsayılan bir değer ayarlayabilirim. Neler oluyor?


1
Bu kullanılmamalıdır. utcnow, UTC saat diliminde naif bir zaman damgasıdır, bununla birlikte, naif zaman damgalarının bunun yerine yerel saat diliminde yorumlanması ihtimali vardır.
Antti Haapala

1
Bu sorunun uzun zaman önce sorulduğunu biliyorum, ancak cevabınızın @Jeff Widman'ın sağladığı gibi değiştirilmelidir, çünkü kayıt oluşturulduğunda tablo sınıfı tanımlandığında tablo sınıfı tanımlandığında "derleme" zaman tarihini kullanacaktır. AFK iseniz, en azından bu yorum, her soru için yorumları dikkatlice kontrol etmeleri için başkalarına bir uyarı verecektir.
David

Yanıtlar:


186

DateTimegiriş olarak varsayılan bir anahtar yoktur. Varsayılan anahtar Columnişleve bir giriş olmalıdır . Bunu dene:

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)

13
Bu doğru değil. Model yükündeki zaman damgası, kaydın eklendiği zaman yerine tüm yeni kayıtlar için kullanılacaktır.
SkyLeach

8
@SkyLeach Bu kod doğrudur, buradan test edebilirsiniz: pastebin.com/VLyWktUn . datetime.datetime.utcnowgeri arama olarak adlandırılıyor.
bux

1
Bu yanıtı kullandım ancak model yükündeki zaman damgası tüm yeni kayıtlar için kullanılıyor.
scottydelta

105
@scottdelta: Kullanmadığınızdan emin olun default=datetime.datetime.utcnow(); utcnowişlevi, modül yükünde değerlendirmenin sonucu değil, geçmek istersiniz .
disfonksiyon

Hala benim için çalışmadı. Jeff-widman'ın yaklaşımı benim için çalıştı:from sqlalchemy.sql import func; created_date = Column(DateTime(timezone=True), server_default=func.now()
tharndt

396

İstemciniz değil DB'nizdeki zaman damgalarını hesaplayın

Akıl sağlığı için, muhtemelen datetimesuygulama sunucusu yerine DB sunucunuz tarafından hesaplanmasını istersiniz . Uygulamadaki zaman damgasının hesaplanması ağ gecikmesi değişken olduğundan, istemciler biraz farklı saat sapması yaşadığından ve farklı programlama dilleri zaman zaman biraz farklı hesapladığından sorunlara yol açabilir.

SQLAlchemy bunu geçerek func.now()veya func.current_timestamp()(birbirlerinin takma adlarıdır) DB'ye zaman damgasının kendisini hesaplamasını söyler.

SQLALchemy's'i kullanın server_default

Ayrıca, DB'ye zaten değeri hesaplamasını söylediğiniz bir varsayılan değer için, genellikle server_defaultyerine kullanmak daha iyidir default. Bu, SQLAlchemy'ye CREATE TABLEdeyimin bir parçası olarak varsayılan değeri geçirmesini söyler .

Örneğin, bu tabloya geçici bir komut dosyası yazarsanız, komut dosyasını server_defaultmanuel olarak bir zaman damgası çağrısı ekleme konusunda endişelenmenize gerek kalmayacak araçları kullanarak veritabanı otomatik olarak ayarlayacaktır.

SQLAlchemy'yi Anlamak onupdate/server_onupdate

SQLAlchemy ayrıca onupdatesatır her güncellendiğinde yeni bir zaman damgası ekler. Yine, DB'ye zaman damgasının kendisini hesaplamasını söylemek en iyisidir:

from sqlalchemy.sql import func

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

Bir server_onupdateparametre var, ancak aksine server_default, aslında hiçbir şey sunucu tarafı ayarlamıyor. Sadece SQLalchemy'ye bir güncelleme gerçekleştiğinde veritabanınızın sütunu değiştireceğini söyler (belki de sütunda bir tetikleyici oluşturdunuz ), böylece SQLAlchemy karşılık gelen nesneyi güncelleyebilmesi için dönüş değerini soracaktır.

Bir potansiyel potansiyel daha var:

Tek bir işlemde bir sürü değişiklik yaparsanız, hepsinin aynı zaman damgasına sahip olduğunu fark edebilirsiniz. Bunun nedeni, SQL standardının CURRENT_TIMESTAMPişlemin başlangıcına göre değerleri döndürdüğünü belirtmesidir .

PostgreSQL SQL dışı standart sağlar statement_timestamp()ve clock_timestamp()hangi yapmak bir işlem içinde değişiklik. Buradaki dokümanlar: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT

UTC zaman damgası

UTC zaman damgalarını kullanmak istiyorsanız func.utcnow(), SQLAlchemy belgelerinde bir uygulama saplaması sağlanır . Yine de, sürücüye özgü uygun işlevleri kendi başınıza sağlamanız gerekir.


1
Artık Postgres'e sadece işlem başlangıç ​​saatini değil, şu anki saati kullanmasını söylemenin bir yolu olduğunu gördüm ... postgres belgelerinde
Jeff Widman

2
func.utcnow () ya da bunun gibi bir şey var mı?
yerassyl

1
@JeffWidman: utcnow için mysql uygulamamız var mı? Ben sadece mssql ve postreg belgelerinde
JavaSa

1
Bu gerçekten harika bir cevap!
John Mutuma

3
server_default=func.now()benim için çalıştı, ama onupdate=func.now()olmadı. Denenmiş onupdate=datetime.datetime.utcnow(parantez olmadan), bu da yardımcı
olmadı

55

Ayrıca sqlalchemy yerleşik işlevini varsayılan olarak kullanabilirsiniz DateTime

from sqlalchemy.sql import func

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

9
Veritabanının kendisi tarafından işlenecek değer değeri server_defaultyerine de kullanabilirsiniz default.
rgtk

2
Tanımlayıcı tanımlandığında func.now () yürütülmez, bu nedenle tüm modeller / alt öğeler (bu bir temel sınıfsa) aynı DT değerine sahip olacaktır. 'Datetime.datetime.utcnow' gibi bir işlev başvurusu ileterek, her biri için ayrı ayrı yürütülür. Bu, 'oluşturulmuş' veya 'güncellenmiş' özellikler için çok önemlidir.
Şubat'ta Metalstorm

10
@Metalstorm Hayır, bu doğru. sqlalchemy.sql.func, geçerli saati değil, sqlalchemy.sql.functions.now örneğini döndüren özel bir durumdur. docs.sqlalchemy.org/tr/latest/core/…
Kris Hardy

Ne yapar timezone=True?
ChaimG

1
@self itibaren dokümantasyon : Doğru, ve arka uçta tarafından destekleniyorsa", 'TIMESTAMP İLE TIMEZONE' üretecek saat dilimi farkında damgaları desteklemeyen backends için, hiçbir etkisi yoktur.. .
ChaimG

7

onupdate=datetime.nowUPDATE'lerin last_updatedalanı da değiştirmesi için büyük olasılıkla kullanmak istiyorsunuz .

SQLAlchemy'nin python tarafından yürütülen işlevler için iki varsayılan değeri vardır.

  • default INSERT üzerindeki değeri yalnızca bir kez ayarlar
  • onupdatedeğeri UPDATE tarihinde de çağrılabilir sonuca ayarlar .

Nedenini bilmiyorum, ama nedense onupdatebenim için hiçbir şey yapmıyor.
Vikas Prasad

1
Sonunda bunu yaparak Postgres db üzerinde çalıştım: created_at = db.Column(db.DateTime, server_default=UtcNow())ve updated_at = db.Column(db.DateTime, server_default=UtcNow(), onupdate=UtcNow())nerede UtcNowolduğu gibi bir sınıf class UtcNow(expression.FunctionElement): type = DateTime()ve var@compiles(UtcNow, 'postgresql') def pg_utc_now(element, compiler, **kw): return "TIMEZONE('utc', CURRENT_TIMESTAMP)"
Vikas Prasad

6

defaultAnahtar kelime parametresi Sütun nesnesine verilmelidir.

Misal:

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

Varsayılan değer, burada şöyle tanımladığım bir çağrılabilir olabilir.

from pytz import timezone
from datetime import datetime

UTC = timezone('UTC')

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

Nereden time_nowgeliyor?
kay - SE kötülük

Teşekkür ederim! Bir şekilde göz ardı ettiğim bu isimde yerleşik bir fonksiyon olduğunu varsaydım.
kay - SE kötülük

veyadatetime.datetime.utcnow
serkef

1

PostgreSQL belgelerine göre, https://www.postgresql.org/docs/9.6/static/functions-datetime.html

now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.

Bu bir özellik olarak kabul edilir: amaç, tek bir işlemin "geçerli" zaman konusunda tutarlı bir fikre sahip olmasını sağlamaktır, böylece aynı işlem içindeki birden fazla değişiklik aynı zaman damgasını taşır.

Sen kullanmak isteyebilirsiniz statement_timestamp veya clock_timestamp Eğer işlem damgası istemiyorsanız.

statement_timestamp ()

geçerli ifadenin başlangıç ​​zamanını döndürür (daha spesifik olarak istemciden en son komut mesajının alındığı zaman). statement_timestamp

clock_timestamp ()

gerçek geçerli zamanı döndürür ve bu nedenle değeri tek bir SQL komutunda bile değişir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.