Reputation: 1779
I am writing a program which uses a database with sqlalchemy as client.
Here is one of my tables
class DownloadRecord(Base):
__tablename__ = "DownloadRecords"
id = Column("Id", Integer, primary_key=True, autoincrement=True)
download_name = Column("DownloadName", Unicode, nullable=False)
download_date = Column(
"DownloadDate", DateTime, default=datetime.datetime.utcnow, nullable=False
)
the column download_date
is defined with a default value, both here and in the server side table. Here is the definition of the column on the mssql server
DownloadDate DATETIME NOT NULL DEFAULT GETDATE()
however I try to add the record DownloadRecord(download_name="new_download_name")
and I get the following exception.
sqlalchemy.exc.IntegrityError: (pyodbc.IntegrityError) ('23000', "[23000] [Microsoft][SQL Server Native Client 11.0][SQL Server]Cannot insert the value NULL into column 'DownloadDate', table 'DownloadRecords'; column does not allow nulls. INSERT fails. (515) (SQLExecDirectW); [23000] [Microsoft][SQL Server Native Client 11.0][SQL Server]The statement has been terminated. (3621)") [SQL: INSERT INTO [DownloadRecords] ([DownloadName], [DownloadDate]) OUTPUT inserted.[Id] VALUES (?, ?)] [parameters: ("new_download_name", None)]
I also tried to make this column nullable but When I added the new row the DownloadDate
column was Null.
How do I make it automatically use the default value?
Upvotes: 0
Views: 1779
Reputation: 16
The problem is incompatibility between the type of the column DownloadDate
and the type of the value you give as its default value on the client side.
The type you used is DateTime
(on the server side as well as the client side).
However, in the following code:
Column("DownloadDate", DateTime, default=datetime.datetime.utcnow, nullable=False)
the return value of datetime.datetime.utcnow()
is a timezone aware object, while SQL Server's DateTime
isn't.
I see two possible solutions:
Change the default value to a callable which returns a datetime
object which is not timezone aware.
Change the type of the DownloadDate
column to a timezone aware type. You can use SQL Server's datetimeoffset
on the server side, and SQLAlchemy's DATETIMEOFFSET
on the client side.
Take a look at Microsoft's docs on date and time types for the full reference.
On another note, consider moving to a code first design, where you define your schema in one place.
Upvotes: -1
Reputation: 34
Searching I found some people fixed by using server_default argument. But this makes the database server responsible to assign the value.
download_date = Column(
"DownloadDate", DateTime, server_default=text('NOW()'), nullable=False
)
Also according to SQLAlchemy documentation, ColumnDefault class is equivalent and it also may work:
download_date = Column(
"DownloadDate", DateTime, ColumnDefault(datetime.datetime.utcnow()), nullable=False
)
But, this uses a scalar instead of a callable.
Hope it works.
Upvotes: 1