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

Фактически, ваш запрос правильный, за исключением опечатки: ваш фильтр исключает все записи: вы должны изменить <=for >=и наоборот:

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
Кстати, вместо этого '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 CAST в столбце, который удаляет время из уравнения => это НЕ означает диапазон со временем! Это работает только тогда, когда время НЕ указано в столбце - вы должны CAST его на Date, как это, или сделать столбец Date, если это 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.