SQLAlchemy: comment filtrer le champ de date?

105

Voici le modèle:

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

Je veux filtrer entre deux dates, par exemple pour choisir tous les utilisateurs dans l'intervalle 18-30 ans.

Comment l'implémenter avec SQLAlchemy?

Je pense à:

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

# means age >= 24 and age <= 27

Je sais que ce n'est pas correct, mais comment faire le correct?

Vitalii Ponomar
la source

Réponses:

181

En fait, votre requête est juste sauf pour la faute de frappe: votre filtre exclut tous les enregistrements: vous devez changer le <=pour >=et 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')

Vous pouvez également utiliser between:

qry = DBSession.query(User).filter(User.birthday.between('1985-01-17', '1988-01-17'))
van
la source
28
Btw, au lieu de '1985-01-17', vous pouvez également utiliser datetime.date(1985, 1, 17)- peut être plus facile à obtenir ou à travailler dans certains environnements.
tossbyte du
5
@rippleslash: vous avez raison, et idéalement, vous devriez utiliser le type de données approprié pour les paramètres. Cependant, toutes les bases de données comprennent également le format ISO 8601 pour les dates, qui se trouve également être l'ordre lexicographique. Pour cette raison, pour des exemples simples, j'utilise généralement des dates au format ISO - plus faciles à lire.
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()

il est égal à:

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

Wish peut vous aider.

un outil
la source
3

si vous voulez obtenir toute la période:

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

Cela signifie que vont: 1985-01-17 00:00 - 17/01/1988 23:59

MrNinjamannn
la source
DANGER: bien que cela puisse être évident pour certains - cela ne fonctionne que parce que le func.datene fait CAST sur la colonne qui supprime le temps de l' équation => cela ne pas plage moyenne avec le temps! Cela ne fonctionne que lorsque l'heure n'est PAS dans la colonne - vous devez le CAST à Date comme ceci, ou créer la colonne Date, une fois que c'est DateHeure ou horodatage - il se termine généralement par 00:00 (MySQL et PostgreSQL le font). Une solution plus générique n'est pas de lancer, mais de définir la date à laquelle vous envoyez .endOfDay () afin que vous l'envoyiez réellement 1988-01-17 23:59:59à la base de données comparez :)
jave.web