SQLAlchemy: як відфільтрувати поле дати?


105

Ось модель:

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

Я знаю, що це не правильно, але як правильно зробити?

Відповіді:


181

Насправді, ваш запит прямо за помилку , окрім: Ваш фільтр за винятком всіх записів: ви повинні змінити <=для >=і навпаки:

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'))

28
Btw, замість цього '1985-01-17', ви також можете використовувати datetime.date(1985, 1, 17)- можливо, у деяких умовах простіше працювати або працювати з ним.
tossbyte

5
@rippleslash: ви праві, і в ідеалі слід використовувати відповідний тип даних для параметрів. Однак усі бази даних розуміють також формат ISO 8601 для дат, який також буває лексикографічним. З цієї причини для простих прикладів я, як правило, використовую дати, відформатовані ISO - легше читати.
ван

4
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

бажання може вам допомогти.


3

якщо ви хочете отримати весь період:

    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 на стовпчику, який видаляє час з рівняння => це НЕ означає діапазон із часом! Це працює лише тоді, коли час НЕ знаходиться у стовпці - вам потрібно КАСИТИ його до такої дати, або внести дату стовпця, як тільки це DateTime або часова мітка - зазвичай це закінчується о 00:00 (обидва MySQL та PostgreSQL роблять це). Більш загальне рішення не гіпсі, але встановити дату, переданому на це .endOfDay () , так що ви на самому справі відправити 1988-01-17 23:59:59в базу даних порівнювати :)
jave.web
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.