SQLAlchemy по умолчанию DateTime
Это моя декларативная модель:
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)
Однако, когда я пытаюсь импортировать этот модуль, я получаю эту ошибку:
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'
Если я использую тип Integer, я могу установить значение по умолчанию. Что происходит?
Ответы
Ответ 1
DateTime
не имеет ключа по умолчанию в качестве входа. Клавиша по умолчанию должна быть введена в функцию Column
. Попробуйте следующее:
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)
Ответ 2
Вычислять метки времени в вашей БД, а не в вашем клиенте
Для здравомыслия вы, вероятно, хотите, чтобы все datetimes
рассчитывались вашим сервером БД, а не сервером приложений. Вычисление метки времени в приложении может привести к проблемам, поскольку задержка в сети является переменной, клиенты испытывают немного различный сдвиг тактовой частоты, а разные языки программирования иногда вычисляют время немного по-разному.
SQLAlchemy позволяет вам сделать это, передавая func.now()
или func.current_timestamp()
(они являются псевдонимами друг друга), который указывает БД рассчитать саму метку времени.
Использовать SQLALchemy server_default
Кроме того, для значения по умолчанию, когда вы уже говорите БД для вычисления значения, обычно лучше использовать server_default
вместо default
по default
. Это говорит SQLAlchemy передать значение по умолчанию как часть оператора CREATE TABLE
.
Например, если вы напишите специальный скрипт для этой таблицы, использование server_default
означает, что вам не нужно беспокоиться о ручном добавлении вызова метки времени в ваш скрипт - база данных установит его автоматически.
Понимание SQLAlchemy onupdate
/server_onupdate
SQLAlchemy также поддерживает onupdate
поэтому при onupdate
обновлении строки вставляется новая timestamp. Опять же, лучше всего сказать БД рассчитать саму метку времени:
from sqlalchemy.sql import func
time_created = Column(DateTime(timezone=True), server_default=func.now())
time_updated = Column(DateTime(timezone=True), onupdate=func.now())
Существует параметр server_onupdate
, но, в отличие от server_default
, он фактически ничего не устанавливает на server_default
. Он просто сообщает SQLalchemy, что ваша база данных изменит столбец при обновлении (возможно, вы создали триггер для столбца), поэтому SQLAlchemy запросит возвращаемое значение, чтобы он мог обновить соответствующий объект.
Еще один потенциальный вопрос:
Вы можете быть удивлены, заметив, что если вы сделаете кучу изменений в одной транзакции, они все будут иметь одну и ту же метку времени. Это потому, что стандарт SQL указывает, что CURRENT_TIMESTAMP
возвращает значения, основанные на начале транзакции.
PostgreSQL обеспечивает не-SQL стандарта statement_timestamp()
и clock_timestamp()
, которые меняются в рамках транзакции. Документы здесь: https://www.postgresql.org/docs/current/static/functions-datetime.html#FUNCTIONS-DATETIME-CURRENT
Метка времени UTC
Если вы хотите использовать метки времени UTC, заглушка реализации func.utcnow()
предоставляется в документации по SQLAlchemy. Вы должны обеспечить соответствующие специфичные для драйвера функции самостоятельно, хотя.
Ответ 3
Вы также можете использовать встроенную функцию sqlalchemy для DateTime
по умолчанию
from sqlalchemy.sql import func
DT = Column(DateTime(timezone=True), default=func.now())
Ответ 4
Параметр ключевого слова default
должен быть присвоен объекту Column.
Пример:
Column(u'timestamp', TIMESTAMP(timezone=True), primary_key=False, nullable=False, default=time_now),
Значение по умолчанию может быть вызываемым, которое здесь определяется следующим образом.
from pytz import timezone
from datetime import datetime
UTC = timezone('UTC')
def time_now():
return datetime.now(UTC)
Ответ 5
Скорее всего, вы захотите использовать onupdate=datetime.now
, чтобы ОБНОВЛЕНИЯ также меняли поле last_updated
.
SQLAlchemy имеет два значения по умолчанию для функций, выполняемых на Python.
default
устанавливает значение на INSERT, только один раз
onupdate
также устанавливает значение для вызываемого результата в UPDATE.
Ответ 6
Согласно документации PostgreSQL, https://www.postgresql.org/docs/9.6/static/functions-datetime.html.
now, CURRENT_TIMESTAMP, LOCALTIMESTAMP return the time of transaction.
Это считается особенностью: цель состоит в том, чтобы позволить одной транзакции иметь согласованное представление о "текущем" времени, так что несколько модификаций в рамках одной транзакции имеют одинаковую отметку времени.
Вы можете использовать statement_timestamp или clock_timestamp, если вы не хотите транзакций метки времени.
statement_timestamp()
возвращает время начала текущего оператора (точнее, время получения последнего командного сообщения от клиента). statement_timestamp
clock_timestamp()
возвращает текущее текущее время, и, следовательно, его значение изменяется даже в пределах одной команды SQL.