155 votes

SQLAlchemy : comment filtrer un champ de date ?

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 le mettre en œuvre 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 pour corriger ?

253voto

van Points 18052

En fait, votre requête est correcte, à l'exception de la coquille : votre filtre exclut tous les enregistrements : vous devriez changer le paramètre <= 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'))

43 votes

En fait, au lieu de '1985-01-17' vous pouvez également utiliser datetime.date(1985, 1, 17) - peuvent être plus faciles à atteindre ou à travailler dans certains environnements.

5 votes

@rippleslash : vous avez raison, et l'idéal est d'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 être l'ordre lexicographique. C'est pourquoi, pour les exemples simples, j'utilise généralement des dates au format ISO - plus faciles à lire.

13voto

MrNinjamannn Points 441

Si vous voulez obtenir le ensemble du site 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 veut dire une portée : 1985-01-17 00:00 - 1988-01-17 23:59

5 votes

DANGER : bien que cela puisse paraître évident pour certains, cela ne fonctionne QUE parce que le func.date fait CAST sur la colonne qui supprime le temps de l'équation \=> cela fait PAS l'intervalle moyen avec le temps ! Cela ne fonctionne que lorsque l'heure n'est PAS dans la colonne - vous devez la CASTER en Date comme ceci, ou faire de la colonne Date, une fois qu'elle est DateTime ou timestamp - elle se termine généralement par 00:00 (MySQL et PostgreSQL font tous deux cela). Une solution plus générique n'est pas de faire un cast, mais de définir la date que vous envoyez à son .endOfDay() de sorte que vous envoyez réellement 1988-01-17 23:59:59 à la base de données comparer :)

7voto

atool Points 361
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

souhait peut vous aider.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X