【问题标题】:SQLAlchemy: how to filter date field?SQLAlchemy:如何过滤日期字段?
【发布时间】:2012-02-12 06:59:29
【问题描述】:

这是型号:

class User(Base):
    ...
    birthday = Column(Date, index=True)   #in database it's like '1987-01-17'
    ...

我想在两个日期之间进行过滤,例如选择间隔 18-30 年的所有用户。

如何用 SQLAlchemy 实现它?

我想到了:

query = DBSession.query(User).filter(
    and_(User.birthday >= '1988-01-17', User.birthday <= '1985-01-17')
) 

# means age >= 24 and age <= 27

我知道这是不正确的,但是如何正确呢?

【问题讨论】:

    标签: python sql database orm sqlalchemy


    【解决方案1】:

    事实上,您的查询是正确的,除了错字:您的过滤器排除了所有记录:您应该将&lt;= 更改为&gt;=,反之亦然:

    qry = DBSession.query(User).filter(
            and_(User.birthday <= '1988-01-17', User.birthday >= '1985-01-17'))
    # or same:
    qry = DBSession.query(User).filter(User.birthday <= '1988-01-17').\
            filter(User.birthday >= '1985-01-17')
    

    你也可以使用between:

    qry = DBSession.query(User).filter(User.birthday.between('1985-01-17', '1988-01-17'))
    

    【讨论】:

    • 顺便说一句,您也可以使用 datetime.date(1985, 1, 17) 而不是 '1985-01-17' - 在某些环境中可能更容易使用或使用。
    • @rippleslash:你是对的,理想情况下应该使用正确的数据类型作为参数。然而,所有数据库也理解日期的 ISO 8601 格式,这也恰好是字典顺序。出于这个原因,对于简单的示例,我通常使用 ISO 格式的日期 - 更易于阅读。
    • 中间示例中的@van 是否包含日期?
    • @rohitwtbs:sqlalchemy 将简单地转换为 BETWEEN 运算符的数据库实现,因此答案将取决于 RDBMS。但我相信它在所有现代 RDBMS 中都具有包容性
    【解决方案2】:

    如果你想得到整个时期:

        from sqlalchemy import and_, func
    
        query = DBSession.query(User).filter(and_(func.date(User.birthday) >= '1985-01-17'),\
                                                  func.date(User.birthday) <= '1988-01-17'))
    

    表示范围:1985-01-17 00:00 - 1988-01-17 23:59强>

    【讨论】:

    • 危险: 虽然这对某些人来说可能很明显 - 这仅适用于 func.date删除的列上执行 CAST等式中的时间 => 这确实 NOT 表示 时间的范围! 这仅在时间不在列中时有效 - 您必须将其转换为 Date像这样,或者创建列日期,一旦它是日期时间或时间戳 - 它通常以 00:00 结束(MySQL 和 PostgreSQL 都这样做)。更通用的解决方案不是强制转换,而是将您发送到它的日期设置为 .endOfDay() 以便您实际上将1988-01-17 23:59:59 发送到数据库比较:)
    【解决方案3】:
    from app import SQLAlchemyDB as db
    
    Chance.query.filter(Chance.repo_id==repo_id, 
                        Chance.status=="1", 
                        db.func.date(Chance.apply_time)<=end, 
                        db.func.date(Chance.apply_time)>=start).count()
    

    等于:

    select
       count(id)
    from
       Chance
    where
       repo_id=:repo_id 
       and status='1'
       and date(apple_time) <= end
       and date(apple_time) >= start
    

    希望能帮到你。

    【讨论】:

      【解决方案4】:

      这是一个与最新的Flask 版本一起使用并使用flask-marshmallow 的版本。

      from datetime import date, timedelta
      
      from flask import jsonify
      
      from app import db, ma
      from app.models import User
      
      from . import main
      
      class UserSchema(ma.Schema):
          class Meta:
              fields = ('forename', 'surname', 'birthday', ...)
      
      
      @main.route('/', methods=('GET',))
      def get_users():
      
          start_range = date.today() + timedelta(years=-30)
          end_range = date.today() + timedelta(years=-18)
      
          users = db.session.query(User).filter(User.birthday.between(start_range, end_range)).all()
      
          users_schema = UserSchema(many=True)
      
          return jsonify(users_schema.dump(users))     
      

      【讨论】:

      • 我觉得你打错了date.today() + timedelta(years=-18)应该叫end_range
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-04
      • 1970-01-01
      • 2021-09-30
      • 2010-12-15
      • 1970-01-01
      相关资源
      最近更新 更多