Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

SQLAlchemy returning strings instead of datetime objects

I'm using SQLAlchemy to connect to a SQL Server database. The table I'm querying has a DATETIME column. On Windows, the resulting attribute on the SQLAlchemy object is a Python datetime object. On Linux, it's a string.

My SQLAlchemy class looks like this

class MyTable(Model):
    id_ = db.Column('Id', db.Integer, primary_key=True, index=True)
    as_of_date = db.Column('AsOfDate', db.DateTime, nullable=False, server_default=db.FetchedValue())
    # Other columns

On Windows, I get this

>>db.session.query(MyTable.as_of_date).first()
datetime.datetime(2006, 11, 30, 0, 0)

On Linux, I get this

>>db.session.query(MyTable.as_of_date).first()
('2006-11-30 00:00:00.00000000',)

My connection strings look like this

Linux
mssql+pyodbc:///?odbc_connect=DRIVER={FreeTDS};Server=my_server;Port=1433;Database=my_database;UID=my_user;PWD=my_password;TDS_Version=8.0;

Windows
mssql+pyodbc://my_user:my_password@my_server/my_database?driver=SQL Server Native Client 11.0

I'm guessing this has something to do with the FreeTDS driver. Although, SQLAlchemy documentation states that

DATE and TIME are supported. Bind parameters are converted to datetime.datetime() objects as required by most MSSQL drivers, and results are processed from strings if needed. The DATE and TIME types are not available for MSSQL 2005 and previous - if a server version below 2008 is detected, DDL for these types will be issued as DATETIME.

How can I fix this so that the Linux calls return datetime objects?

like image 570
Kris Harper Avatar asked Feb 09 '17 16:02

Kris Harper


People also ask

What does SQLAlchemy query return?

It returns an instance based on the given primary key identifier providing direct access to the identity map of the owning Session. It creates a SQL JOIN against this Query object's criterion and apply generatively, returning the newly resulting Query. It returns exactly one result or raise an exception.

What is all () in SQLAlchemy?

method sqlalchemy.orm.Query. all() Return the results represented by this Query as a list. This results in an execution of the underlying SQL statement. The Query object, when asked to return either a sequence or iterator that consists of full ORM-mapped entities, will deduplicate entries based on primary key.

Is SQLAlchemy efficient?

SQLAlchemy leverages powerful common statements and types to ensure its SQL statements are crafted efficiently and properly for each database type and vendor without you having to think about it. This makes it easy to migrate logic from Oracle to PostgreSQL or from an application database to a data warehouse.

What is SQLAlchemy selectable?

The term “selectable” refers to any object that rows can be selected from; in SQLAlchemy, these objects descend from FromClause and their distinguishing feature is their FromClause.


1 Answers

The issue was that the column was actually DATETIME2 (not DATETIME) and the Linux box had FreeTDS 0.91 installed. In order for FreeTDS to fully support DATETIME2 columns you need to be running FreeTDS 0.95 or newer and using TDS protocol version 7.3 or 7.4.

(Note that TDS_Version "8.0" is really just an alias for version 7.1, so it is not newer than 7.3. Ref: here.)

Of course, your other option is to switch from FreeTDS_ODBC to the Microsoft ODBC Driver for SQL Server on Linux. That, combined with pyodbc, is a configuration that is officially supported by Microsoft.

like image 121
Gord Thompson Avatar answered Sep 24 '22 10:09

Gord Thompson