我在sqlalchemy-0.7中有一个带有Date列的类。我可以拥有一个column_property或类似的东西让我成为一年,让我轻松过滤它吗?我该怎么写呢?
IE,我想要(声明性语法):
class Foo(Base):
id = Column(Integer, primary_key=True)
date = Column(Date(), nullable=False)
year = column_property(something here)
# later on
q = session().query(Foo).filter_by(year=2011)
答案 0 :(得分:5)
当然你可以定义这样的属性:
year = column_property(extract('year', date))
但你真的需要吗?您可以按年度过滤,而不会通过重写过滤条件来定义此属性:
query(Foo).filter(extract('year', Foo.date)==2011)
<强>更新强>
虽然这个解决方案看起来很简单但它也有一个缺点:WHERE子句中的这种情况永远不会在日期字段上使用索引。具有大量行和高选择性条件会对性能产生很大影响。因此,您可能希望重写将导致RANGE INDEX SCAN而不是FULL TABLE SCAN的条件(如Simon的评论中所述):
start = datetime.date(year, 1, 1)
end = datetime.date(year, 12, 31)
query(Foo).filter(Foo.date.between(start, end))
也可以定义具有此类行为的属性,您只需重新定义比较器:
class YearComparator(ColumnProperty.Comparator):
def __eq__(self, year):
if isinstance(year, int):
column = self.prop.columns[0].get_children()[0].expr
start = datetime.date(year, 1, 1)
end = datetime.date(year, 12, 31)
return column.between(start, end)
else:
# It can be a column or exression which we can't handle such way
return ColumnProperty.Comparator.__eq__(self, year)
# __lt__, __gt__ etc. are very similar to __eq__
def year_property(date_column, **kwargs):
kwargs.setdefault('comparator_factory', YearComparator)
return column_property(extract('year', date_column), **kwargs)
class Foo(Base):
__tablename__ = 'Foo'
id = Column(Integer, primary_key=True)
date = Column(Date, index=True)
year = year_property(date)