SQLAlchemy: tarih alanı nasıl filtrelenir?


104

İşte model:

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

Örneğin 18-30 yıl aralığında tüm kullanıcıları seçmek için iki tarih arasında filtre uygulamak istiyorum.

SQLAlchemy ile nasıl uygulanır?

Ben düşünüyorum:

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

# means age >= 24 and age <= 27

Bunun doğru olmadığını biliyorum ama nasıl düzeltilebilir?

Yanıtlar:


180

Aslında, sorgunuz yazım hatası dışında doğrudur: filtreniz tüm kayıtları hariç tutar: <=for >=ve tersini değiştirmelisiniz:

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

Ayrıca şunları kullanabilirsiniz between:

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

28
Btw yerine, '1985-01-17'kullanabilirsiniz datetime.date(1985, 1, 17)- bazı ortamlarda ulaşmak veya çalışmak daha kolay olabilir.
tossbyte

5
@rippleslash: haklısınız ve ideal olarak, parametreler için uygun veri türünü kullanmalısınız. Bununla birlikte, tüm veritabanları, aynı zamanda sözlüksel sıralama da olan tarihler için ISO 8601 biçimini de anlar. Bu nedenle basit örnekler için genellikle ISO formatlı tarihleri ​​kullanıyorum - okuması daha kolay.
minibüs

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

şuna eşittir:

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

dilek size yardımcı olabilir.


3

tüm süreyi almak istiyorsanız :

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

Bu, aralık anlamına gelir: 1985-01-17 00:00 - 1988-01-17 23:59


TEHLİKE: Bu bazı bariz olabilir ancak - çünkü bu SADECE çalışır func.dateyapar CAST kolonunda denklemden zaman kaldırır => yapar DEĞİL ile ortalama aralık zaman! Bu, yalnızca saat sütunda DEĞİLSE işe yarar - bunu Tarihe bu şekilde CAST yapmalısınız veya DateTime veya zaman damgası olduktan sonra Date sütununu yapmalısınız - genellikle 00:00 ile biter (hem MySQL hem de PostgreSQL bunu yapar). Daha genel bir çözüm, yayınlamak değil, göndereceğiniz tarihi .endOfDay () olarak ayarlamaktır, böylece aslında 1988-01-17 23:59:59veritabanına karşılaştırma gönderebilirsiniz :)
jave.web
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.