为了使用自定义范围类型你need to dig a bit deeper:
在实例化使用这些列类型的模型时,您应该传递用于列类型的 DBAPI 驱动程序所期望的任何数据类型。对于psycopg2,这些是NumericRange、DateRange、DateTimeRange 和DateTimeTZRange或您在register_range() 注册的课程。
换句话说,您必须使用 DBAPI 注册您的自定义范围类型(通常是psycopg2)并创建 SQLAlchemy 类型以匹配注册的类型。 register_range() 采用 PostgreSQL range 类型的名称,Range 的(严格)子类和用于获取 oid 的连接/游标。它可以全局注册新的范围类型,也可以本地注册到给定的连接或游标:
In [2]: import psycopg2.extras
创建模型实例时应使用的值类型:
In [3]: class TimeRange(psycopg2.extras.Range):
...: pass
...:
在 SQLAlchemy 中使用 raw_connection() 获取底层 psycopg2 连接的代理。注册可能应该在实际实现中的设置函数中完成:
In [4]: conn = engine.raw_connection()
In [5]: cur = conn.cursor()
In [6]: psycopg2.extras.register_range('timerange', TimeRange, cur, globally=True)
Out[6]: <psycopg2._range.RangeCaster at 0x7f1c980dbe80>
In [7]: cur.close()
In [8]: conn.close()
接下来创建 SQLAlchemy 范围类型以匹配注册的TimeRange。 TypeDecorator 不适合,因为您没有使用现有类型。 UserDefinedType 应该是所有全新类型的基础。对于范围运算符,包括 RangeOperators mixin:
它被 postgres 方言中提供的所有范围类型使用,并且可能用于您自己创建的任何范围类型。
其余的几乎都是直接从the predefined range types复制过来的:
In [11]: from sqlalchemy.dialects import postgresql
In [13]: from sqlalchemy import types as sqltypes
In [14]: class TIMERANGE(postgresql.ranges.RangeOperators, sqltypes.UserDefinedType):
...: def get_col_spec(self, **kw):
...: return 'timerange'
这只是反射所必需的。
In [16]: postgresql.base.ischema_names['timerange'] = TIMERANGE
然后创建您的表格并照常使用:
In [17]: schedule = Table('schedule', metadata, autoload=True, autoload_with=engine)
In [18]: schedule
Out[18]: Table('schedule', MetaData(bind=Engine(postgresql:///sopython)), Column('id', INTEGER(), table=<schedule>, primary_key=True, nullable=False), Column('time_range', TIMERANGE(), table=<schedule>), schema=None)
In [19]: session.query(schedule).all()
Out[19]:
[(1, TimeRange(datetime.time(8, 0), datetime.time(10, 0), '[]')),
(2, TimeRange(datetime.time(10, 0), datetime.time(12, 0), '[]'))]
In [20]: session.query(schedule).\
...: filter(schedule.c.time_range.contains(time(9, 0))).\
...: all()
2017-04-11 10:01:23,864 INFO sqlalchemy.engine.base.Engine SELECT schedule.id AS schedule_id, schedule.time_range AS schedule_time_range
FROM schedule
WHERE schedule.time_range @> %(time_range_1)s
2017-04-11 10:01:23,864 INFO sqlalchemy.engine.base.Engine {'time_range_1': datetime.time(9, 0)}
Out[20]: [(1, TimeRange(datetime.time(8, 0), datetime.time(10, 0), '[]'))]