SQLAlchemy: como filtrar o campo de data?

105

Aqui está o modelo:

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

Quero filtrar entre duas datas, por exemplo, para escolher todos os usuários no intervalo de 18 a 30 anos.

Como implementá-lo com SQLAlchemy?

Eu penso em:

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

# means age >= 24 and age <= 27

Eu sei que isso não é correto, mas como fazer correto?

Vitalii Ponomar
fonte

Respostas:

181

Na verdade, sua consulta está correta, exceto pelo erro de digitação: seu filtro está excluindo todos os registros: você deve alterar o <=para >=e vice-versa:

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

Você também pode usar between:

qry = DBSession.query(User).filter(User.birthday.between('1985-01-17', '1988-01-17'))
furgão
fonte
28
Aliás, em vez de '1985-01-17', você também pode usar datetime.date(1985, 1, 17)- pode ser mais fácil de acessar ou trabalhar em alguns ambientes.
tossbyte
5
@rippleslash: você está certo, e o ideal é usar o tipo de dados adequado para os parâmetros. No entanto, todos os bancos de dados também entendem o formato ISO 8601 para datas, que também acontece em ordem lexicográfica. Por esse motivo, para exemplos simples, geralmente uso datas formatadas em ISO - mais fáceis de ler.
van
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()

é igual a:

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

desejo pode ajudá-lo.

uma ferramenta
fonte
3

se você deseja obter todo o período:

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

Isso significa variam: 1985/01/17 00:00 - 1988/01/17 23:59

MrNinjamannn
fonte
PERIGO: embora isto possa ser óbvio para alguns - isso só funciona porque o func.datefaz ELENCO na coluna que remove o tempo a partir da equação => isso faz NÃO gama média com o tempo! Isso só funciona quando o tempo NÃO está na coluna - você deve CAST para Date assim, ou fazer a coluna Date, uma vez que é DateTime ou timestamp - geralmente termina com 00:00 (ambos MySQL e PostgreSQL fazem isso). Uma solução mais genérica não é lançar, mas definir a data que você está enviando em .endOfDay () para que você realmente envie 1988-01-17 23:59:59para o banco de dados compare :)
jave.web