在SQLAlchemy中总结日期差异

时间:2016-11-20 22:38:57

标签: python mysql sqlalchemy

我正在撰写一本非常基本的日记应用程序。我在SQLAlchemy中有以下模型:

association_table = Table('association', Base.metadata,
    Column('category_id', Integer, ForeignKey('category.id')),
    Column('entry_id', Integer, ForeignKey('entry.id'))
)

class Category(Base):
    __tablename__ = 'category'

    id = Column(Integer, primary_key=True)
    name = Column(String(100), unique=True)
    entries = relationship('Entry', secondary=association_table,
                           back_populates='categories')

class Entry(Base):
    __tablename__ = 'entry'

    id = Column(Integer, primary_key=True)
    text = Column(String(200))
    started = Column(DateTime)
    ended = Column(DateTime)
    categories = relationship('Category', secondary=association_table,
                              back_populates='entries')

我希望所有条目都标记为' work',然后按Entry.text对其进行分组(这将是项目名称)。我基本上想看看我在每个项目上工作了多长时间。所以我写下以下内容:

from sqlalchemy.sql import func
# s is the Session
work = s.query(Category).filter(Category.name=='work').first()
projects = (s.query(Entry.text, 
                    func.sum(Entry.ended-Entry.started)
                         .label('duration'))
              .filter(Entry.categories.contains(work))
              .group_by(Entry.text)
              .order_by('duration desc'))

这似乎应该有效;实际上,当我直接对MySQL数据库运行它时会这样做:

>>> print str(projects)
SELECT entry.text AS entry_text, sum(entry.ended - entry.started) AS duration 
FROM entry, association AS association_1 
WHERE entry.id = association_1.entry_id AND %(param_1)s = association_1.category_id
GROUP BY entry.text ORDER BY duration desc

但是,当我尝试运行此查询时,出现以下错误:

>>> projects.all()
[...trace back...]
TypeError: unsupported operand type(s) for -: 'Decimal' and 'datetime.datetime'

我猜测SA正在尝试进行一些处理并失败?有没有办法让这个查询起作用?

1 个答案:

答案 0 :(得分:0)

似乎SQLAlchemy在数据库是MySQL时无法进行Interval(timedelta)算法。我能够使用它:

class tsum(GenericFunction):
    type = Float()
    name = 'SUM'

projects = s.query(Entry.text, (func.t_sum(
                func.time_to_sec(func.timediff(Entry.ended, Entry.started)/60)
                  .label('duration'))
            .filter(Entry.categories.contains(work))
            .group_by(Entry.text)
            .order_by('duration desc')

返回元组(text, minutes)