【问题标题】:SqlAlchemy filter by time differenceSqlAlchemy 按时差过滤
【发布时间】:2014-04-21 05:43:34
【问题描述】:

我是 SQLAlchemy 的新手(但不是那么新)。我正在为一个项目使用 0.9.3 版本。我想查询 SQLite 数据库过滤结果以获取那些没有时间戳或自上次更新以来超过 24 小时的对象(在同一列上)。

问题是,我不知道如何实现时间过滤部分,我做了一个 IPython Notebook 会话,所以人们可以看看尝试了多长时间来寻找我的问题的答案:

在 [1] 中:

from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, Unicode, DateTime, Integer, create_engine
from sqlalchemy.orm import sessionmaker, relationship, backref
from datetime import datetime

engine = create_engine('sqlite:///:memory:')
Base = declarative_base()
Session = sessionmaker(bind=engine)
session = Session()

在 [2] 中:

class Product(Base):
    __tablename__ = "product"

    id = Column(Integer, primary_key=True)
    name = Column(Unicode(140), unique=True, nullable=False)
    department = Column(Unicode(20))
    added = Column(DateTime, default=datetime.now)
    last_time_parsed = Column(DateTime)

    def repr(self):
        return "<Product(name=%s, department=%s, added=%s, last_time_parsed=%s)>" % (
                            self.name, self.department, self.added, self.last_time_parsed)

在 [3] 中:

# create the tables
Base.metadata.create_all(engine)

在 [4] 中:

# create a false product
p1 = Product(name="Product X")
p2 = Product(name = "Product Y")
p3 = Product(name = "Product Z")

在 [5] 中:

session.add(p1)
session.add(p2)
session.add(p3)
session.commit()

/home/jorge/projects/project1/lib/python2.7/site-packages/sqlalchemy/engine/default.py:525: SAWarning: Unicode type received non-unicode bind param value.
  param.append(processors[key](compiled_params[key]))

在 [7] 中:

q = session.query(Product).filter(Product.last_time_parsed == None).filter(Product.last_time_parsed > 24)

在 [9] 中:

print q.first().name

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-9-377361de0bab> in <module>()
----> 1 print q.first().name

AttributeError: 'NoneType' object has no attribute 'name'

在 [14] 中:

q = session.query(Product).filter(Product.last_time_parsed == None)

在 [15] 中:

print q.first().name

Product X

在 [16] 中:

q = session.query(Product).filter(Product.last_time_parsed < 24)
print q.first().name

---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-16-b10ccbb5d88d> in <module>()
      1 q = session.query(Product).filter(Product.last_time_parsed < 24)
----> 2 print q.first().name

AttributeError: 'NoneType' object has no attribute 'name'

在 [20] 中:

q = session.query(Product).filter(Product.added > 24)
print q.first().name

Product X

在 []:

在input 20 中,我知道Product.added 是DateTime 数据类型(我只是用来测试,因为它是唯一保存DateTime 值的列)。我不明白的是逻辑陈述。如果是Product.added &lt; 24(如input 16 所示)而不是Product.added &gt; 24,我将不会从数据库中获得任何对象。那么,通过数字24 对数据库的理解究竟是什么? 24 分钟? 24小时? 24 秒? 24 天?

那么,我该如何过滤数据以获取没有时间戳或更新时间超过 24 小时的数据?

谢谢:)

【问题讨论】:

  • 而不是值24,你能不能与当前时间前24小时的datetime值进行比较?例如datetime.now() - timedelta(hours=24)
  • 我刚刚发现了这一点。但我做了类似onedayold = datetime.timedelta(hours=24) 的操作,然后在查询中使用它来过滤所有不超过 24 小时的数据。喜欢:q = session.query(Product).filter(Product.added &lt; onedayold); qn = q.all(); print qn 产生[],因为添加的数据不超过 24,所以结果正确。但是,我仍然错过了包含 last_time_parsed 列的每个产品的步骤 None 具有价值。
  • 您无法将 added 与 timedelta 对象进行比较。 2014-03-15 08:12:33 少于 24 小时是什么意思?您必须将其与 2014-03-14 15:52:40 进行比较。由于 2014-03-15 08:12:33 发生在 2014-03-14 15:52:40 之后,因此它更大。因此,要查找 datetime 是否在过去 24 小时内出现,您必须执行 Product.added &gt; datetime.now() - timedelta(hours=24)。

标签: python time orm sqlalchemy python-datetime


【解决方案1】:

您不需要使用union,但WHERE 子句的简单OR 部分就可以了:

since = datetime.now() - timedelta(hours=24)
q = (session.query(Product).filter(or_(
            Product.last_time_parsed == None,
            Product.last_time_parsed < since)))

【讨论】:

    【解决方案2】:

    所以,我发现了如何实现我想要的。感谢@univerio 的更正!

    我将发布整个 IPython Notebook 会话 :)

    在 [1] 中:

    from sqlalchemy.ext.declarative import declarative_base
    from sqlalchemy import Column, Unicode, DateTime, Integer, create_engine
    from sqlalchemy.orm import sessionmaker, relationship, backref
    import datetime
    
    engine = create_engine('sqlite:///:memory:')
    Base = declarative_base()
    Session = sessionmaker(bind=engine)
    session = Session()
    

    在 [2] 中:

    class Product(Base):
        __tablename__ = "product"
    
        id = Column(Integer, primary_key=True)
        name = Column(Unicode(140), unique=True, nullable=False)
        department = Column(Unicode(20))
        added = Column(DateTime, default=datetime.datetime.now)
        last_time_parsed = Column(DateTime)
    
        def repr(self):
            return "<Product(name=%s, department=%s, added=%s, last_time_parsed=%s)>" % (
                                self.name, self.department, self.added, self.last_time_parsed)
    

    在 [3] 中:

    # create the tables
    Base.metadata.create_all(engine)
    

    在 [4] 中:

    # create a false product
    twodaysinthefuture = datetime.datetime.now() + datetime.timedelta(hours=48)
    p1 = Product(name="Product X")
    p2 = Product(name = "Product Y")
    p3 = Product(name = "Product Z")
    x1 = Product(name = "Product older than 24 hours 1", last_time_parsed=twodaysinthefuture)
    x2 = Product(name = "Product older than 24 hours 2", last_time_parsed=twodaysinthefuture)
    x3 = Product(name = "Product older than 24 hours 3", last_time_parsed=twodaysinthefuture)
    

    在 [5] 中:

    session.add(p1)
    session.add(p2)
    session.add(p3)
    session.add(x1)
    session.add(x2)
    session.add(x3)
    session.commit()
    
    /home/jorge/coders/PPH/clientes/robert_s/playcomscrap/lib/python2.7/site-packages/sqlalchemy/engine/default.py:525: SAWarning: Unicode type received non-unicode bind param value.
      param.append(processors[key](compiled_params[key]))
    

    在 [6] 中:

    onedayearly = datetime.timedelta(hours=24)
    print onedayearly
    since = datetime.datetime.now() - onedayearly
    
    1 day, 0:00:00
    

    在 [7] 中:

    q1 = session.query(Product).filter(Product.last_time_parsed < since) # filter-out those rows with less than 24 hours, right?
    q2 = session.query(Product).filter(Product.last_time_parsed == None) # I'm interested on those products with no time stamp yet, too.
    q3 = q1.union(q2).order_by(Product.id) # aaaaand, done!
    

    在 [8] 中:

    # testing
    for row in q3.all():
        print row.name, row.last_time_parsed
    
    Product X None
    Product Y None
    Product Z None
    Product older than 24 hours 1 2014-03-17 17:26:03.899875
    Product older than 24 hours 2 2014-03-17 17:26:03.899875
    Product older than 24 hours 3 2014-03-17 17:26:03.899875
    

    在 []:

    【讨论】:

    • 您不需要使用union,但WHERE 子句的简单OR 部分可以:q = (session.query(Product).filter(or_( Product.last_time_parsed == None, Product.last_time_parsed &gt; 24 )) )
    猜你喜欢
    • 2016-04-23
    • 2016-11-04
    • 2019-04-15
    • 2012-01-23
    • 2017-08-04
    • 2019-12-26
    • 1970-01-01
    • 2020-08-25
    相关资源
    最近更新 更多