【问题标题】:Find average date in sqlalchemy在 sqlalchemy 中查找平均日期
【发布时间】:2018-09-22 21:17:27
【问题描述】:

我有两张桌子。 Foo 和 Bar。

class Foo(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  bars = db.relationship('Bar', backref='foo', lazy='dynamic')

class Bar(db.Model):
  id = db.Column(db.Integer, primary_key=True)
  date = db.Column(db.DateTime, default=datetime.utcnow)
  foo_id= db.Column(db.Integer, db.ForeignKey('foo.id'))

我怎样才能在 Foo 中拥有一个可以从所有条形图中找到平均日期的混合属性。我已经尝试了以下,它不会产生任何错误,但没有给出预期的结果

@hybrid_property
  def baz(self):
    return db.select([db.func.avg(Bar.date)]) \
      .where(Bar.foo_id == self.id) \
      .label('baz')

我做错了什么?

【问题讨论】:

    标签: python sqlalchemy flask-sqlalchemy


    【解决方案1】:

    这是一个棘手的问题。

    我不确定在 DateTime 对象上应用 avg() 效果是否很好。 如果我是你,我会以秒为单位计算该字段的平均值。 为此,您可以在 Bar 中使用 hybrid_propertyexpression,将 date 字段转换为秒:

    class Bar(db.Model):
      id = db.Column(db.Integer, primary_key=True)
      date = db.Column(db.DateTime)
      foo_id= db.Column(db.Integer, db.ForeignKey('foo.id'))
    
      @hybrid_property
      def date_seconds(self):
        return time.mktime(self.date.timetuple())
    
      @date_seconds.expression
      def date_seconds(cls):
        return time.mktime(cls.date.timetuple())
    

    然后使用这个date_seconds 计算平均秒数,并将其转换回可读的时间格式。

    【讨论】:

    • 这似乎是回答我的问题的正确途径,但我在这部分 cls.date.timetuple() 上收到错误 TypeError: 'NoneType' object is not callable
    • 确实,在尝试了基于此方法的多种解决方案后,我得到了同样的错误,也许其他人可以帮助解决这个问题?很抱歉没有解决,但我确信我们走在正确的道路上。
    • 问题是您不能将检测属性cls.date 视为date_seconds.expression 中的Python 日期对象。它应该用于形成合适的 SQL 表达式。
    【解决方案2】:

    感谢question / answer,我设法解决了这个问题

    我创建了一个自定义类型,将日期时间存储为自 1970 年 1 月 1 日以来的秒数。(UTC)

    class IntegerDate(types.TypeDecorator):
      impl = types.Integer
    
      def process_bind_param(self, value, dialect):
        return value.replace(tzinfo=timezone.utc).timestamp() * 1000
    
      def process_result_value(self, value, dialect):
        return datetime.utcfromtimestamp(value / 1000)
    

    并将此 date = db.Column(db.DateTime) 更改为此 date = db.Column(IntegerDate)

    然后我可以得到平均值

    @hybrid_property
      def baz(self):
        return db.select([db.func.avg(Bar.date)]) \
          .where(Bar.foo_id == self.id) \
          .label('baz')
    

    【讨论】:

      猜你喜欢
      • 2011-01-18
      • 1970-01-01
      • 1970-01-01
      • 2013-05-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-28
      • 1970-01-01
      相关资源
      最近更新 更多