use*_*863 2 python sqlalchemy flask-sqlalchemy
环境:python 3.8、flask-sqlalchemy、postgres
class User(db.Model):
name = db.Column(db.Text)
birthday = db.Column(db.DateTime)
@classmethod
def upcoming_birthdays(cls):
return (cls.query
.filter("??")
.all()
)
Run Code Online (Sandbox Code Playgroud)
我想创建一个 sqlalchemy 查询来过滤 X 天内即将生日的用户。我考虑过使用该extract函数从生日中提取月份和日期,但这对于月底或年底的日子不起作用。我还考虑过尝试将生日转换为儒略日期以进行比较,但我不知道该怎么做。
例如,如果今天是 2020 年 8 月 30 日,它将返回用户的生日
感谢您的帮助
您可以通过如下简单查询来实现您的目标:
q = (
db.session.query(User)
.filter(has_birthday_next_days(User.birthday, 7))
)
Run Code Online (Sandbox Code Playgroud)
这不是 @classmethod on User,但如果您愿意,您可以将解决方案转换为一个。
剩下要做的就是实际实现has_birthday_next_days(...),如下所示,主要是原则的文档:
def has_birthday_next_days(sa_col, next_days: int = 0):
"""
sqlalchemy expression to indicate that an sa_col (such as`User.birthday`)
has anniversary within next `next_days` days.
It is implemented by simply checking if the 'age' of the person (in years)
has changed between today and the `next_days` date.
"""
return age_years_at(sa_col, next_days) > age_years_at(sa_col)
Run Code Online (Sandbox Code Playgroud)
可以有多种实现,age_years_at下面只是一种可能性,具体为postgresql(包括所需的导入):
import datetime
import sqlalchemy as sa
def age_years_at(sa_col, next_days: int = 0):
"""
Generates a postgresql specific statement to return 'age' (in years)'
from an provided field either today (next_days == 0) or with the `next_days` offset.
"""
stmt = func.age(
(sa_col - sa.func.cast(datetime.timedelta(next_days), sa.Interval))
if next_days != 0
else sa_col
)
stmt = func.date_part("year", stmt)
return stmt
Run Code Online (Sandbox Code Playgroud)
最后q = db.session.query(User).filter(has_birthday_next_days(User.birthday, 30)),生成所需的查询:
SELECT "user".id,
"user".name,
"user".birthday
FROM "user"
WHERE date_part(%(date_part_1)s, age("user".birthday - CAST(%(param_1)s AS INTERVAL)))
> date_part(%(date_part_2)s, age("user".birthday))
{'date_part_1': 'year', 'param_1': datetime.timedelta(days=30), 'date_part_2': 'year'}
Run Code Online (Sandbox Code Playgroud)
好处:使用泛型函数实现此功能后,它不仅可以用于列User.birthday,还可以用于任何其他类型兼容的值。此外,这些函数可以在语句的select和部分中单独使用。where例如:
q = (
db.session.query(
User,
age_years_at(User.birthday).label("age_today"),
age_years_at(User.birthday, 7).label("age_in_a_week"),
has_birthday_next_days(User.birthday, 7).label("has_bday_7-days"),
has_birthday_next_days(User.birthday, 30).label("has_bday_30-days"),
)
.filter(has_birthday_next_days(User.birthday, 30))
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
895 次 |
| 最近记录: |