SQLAlchemy: come filtrare il campo della data?


105

Ecco il modello:

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

Voglio filtrare tra due date, ad esempio per scegliere tutti gli utenti nell'intervallo 18-30 anni.

Come implementarlo con SQLAlchemy?

Penso a:

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

# means age >= 24 and age <= 27

So che non è corretto, ma come correggerlo?

Risposte:


181

In effetti, la tua query è corretta tranne che per l'errore di battitura: il tuo filtro esclude tutti i record: dovresti cambiare il <=per >=e viceversa:

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

Inoltre puoi usare between:

qry = DBSession.query(User).filter(User.birthday.between('1985-01-17', '1988-01-17'))

28
A proposito, invece di '1985-01-17', puoi anche usare datetime.date(1985, 1, 17)- potrebbe essere più facile da raggiungere o lavorare in alcuni ambienti.
tossbyte

5
@rippleslash: hai ragione, e idealmente si dovrebbe usare il tipo di dati corretto per i parametri. Tuttavia, tutti i database comprendono anche il formato ISO 8601 per le date, che è anche un ordine lessicografico. Per questo motivo, per esempi semplici, generalmente uso date in formato ISO - più facili da leggere.
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()

è uguale a:

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

desiderio può aiutarti.


3

se vuoi ottenere l' intero periodo:

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

Ciò significa intervallo: 1985-01-17 00:00 - 1988-01-17 23:59


PERICOLO: anche se questo potrebbe essere ovvio per alcuni - questo funziona solo perché la func.datefa CAST sulla colonna, che elimina il tempo dall'equazione => questo non fa NON range medio con il tempo! Funziona solo quando l'ora NON è nella colonna: devi eseguire il CAST in Date in questo modo, o creare la colonna Date, una volta che è DateTime o timestamp - di solito finisce con 00:00 (sia MySQL che PostgreSQL lo fanno). Una soluzione più generica non è quella di eseguire il cast, ma di impostare la data di invio al suo .endOfDay () in modo da inviare effettivamente 1988-01-17 23:59:59al confronto del database :)
jave.web
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.