1

I am using the custom type form this answer, which is quite similar to the one recommended in the SqlAlchemy documentation, let me reproduce it here for a self-contained question:

from sqlalchemy import types
from datetime import datetime, timezone

class UTCDateTime(types.TypeDecorator):

    impl = types.DateTime

    def process_bind_param(self, value, engine):
        if value is None:
            return
        if value.utcoffset() is None:
            raise ValueError(
                'Got naive datetime while timezone-aware is expected'
            )
        return value.astimezone(timezone.utc)

    def process_result_value(self, value, engine):
        if value is not None:
            print('passed here')
            return value.replace(tzinfo=timezone.utc)

If I query like this:

session.query(Table).filter_by(...).first()

.. things works as expected, the method process_result_value runs and my datetime objects come with the UTC tzinfo.

However, if I query like this:

db.query(User).from_statement(text("SELECT * from table where ...")).first()

.. then the method process_result_value runs (I know because I see the print statements in the console), but the returned values do not have the tzinfo from the result.

I'm using SqlAlchemy 1.3.23.

My question is: is this expected behavior? Is there a workaround for this?

Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107

1 Answers1

0

The fix for my problem was to not rely on the textual replace * by id in my textual query.

It's not documented on Query.from_statement, but I've found out that I can use it with a query that returns only the primary keys and let SqlAlchemy resolve the remaining fields.

This solves the problem because SqlAlchemy will not do the textual mapping from the result of the SQL query directly, and does the mapping correctly, at the cost of making one extra query for each resulting id.

Elias Dorneles
  • 22,556
  • 11
  • 85
  • 107