SqlAlchemy фильтр по разнице во времени

Я новичок (но не такой новый) в 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 < 24 (как показано на input 16) вместо Product.added > 24 Я бы не получил объект из базы данных. Итак, по количеству 24 что на самом деле понимает база данных? 24 минуты? 24 часа? 24 секунды? 24 дня?

Итак, опять же, как мне отфильтровать данные, чтобы получить данные, которые не имеют отметки времени или которые были обновлены более 24 часов назад?

Спасибо:)

2 ответа

Решение

Вам не нужно использовать union, но просто OR часть WHERE пункт будет делать:

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

Итак, я узнал, как добиться того, чего хотел. Спасибо @ 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

В []:

Другие вопросы по тегам