我正在尝试在应用程序中管理api密钥。
假设此模型:
class APIKey(db.Model):
__tablename__ = 'api_keys'
...
daily_reset_time = db.Column(db.Integer) # daily reset hour maybe use Interval or Time type here?
daily_limit = db.Column(db.Integer)
per_second_limit = db.Column(db.Integer)
_calls_made = db.Column(db.Integer, default=0)
last_started = db.Column(db.DateTime)
last_ended = db.Column(db.DateTime)
...
@property
def last_used(self):
return self.last_ended if self.last_ended is not None else self.last_started
一些API的每日限制会在特定时间重置。目前,我将此时间存储为代表每日重置时间的整数(也许将其存储为间隔或时间类型会更合适)。我希望能够针对calls_made
,甚至更好的calls_remaining
字段进行查询。为此,我将必须计算上一次重置时间,并查看last_used
属性是否在daily_reset_time
之前发生,以确定是否发生了重置,并因此通过设置{{ 1}}到0。instance属性通过在_calls_made
对象上使用.replace
方法来实现。
datetime
这显然在混合属性表达式中不起作用,因为datetime replace方法中使用的值将是@hybrid_property
def previous_reset(self):
if self.daily_reset_time is not None:
now = datetime.utcnow()
if now.hour >= self.daily_reset_time:
return now.replace(
hour=self.daily_reset_time,
minute=0,
second=0,
microsecond=0
)
else:
return now.replace(
hour=self.daily_reset_time,
minute=0,
second=0,
microsecond=0
) - timedelta(days=1)
实例:
Column
查看postgres的datetime函数后,我可能需要更多类似以下内容来代替@previous_reset.expression
def previous_reset(cls):
now = datetime.utcnow()
return case(
[
( # its later than the daily reset time
and_(cls.daily_reset_time.isnot(None),
cls.daily_reset_time <= now.hour),
now.replace(
hour=cls.daily_reset_time, # this is a valueerror
minute=0,
second=0,
microsecond=0
)
),
(
and_(cls.daily_reset_time.isnot(None),
cls.daily_reset_time >= now.hour),
(now - timedelta(days=1)).replace(
hour=cls.daily_reset_time,
minute=0,
second=0,
microsecond=0
)
),
],
else_=None
)
调用作为case表达式的返回值:
now.replace
但这还缺少一些东西...
如何在混合属性表达式中计算此值?是否有更好的方法来解决此问题,因为我可能还必须添加一个信号,以检查是否应重置func.date_trunc('days', func.timezone('utc', func.current_timestamp)) + f"interval '{cls.daily_reset_time}' hours'"
属性?
答案 0 :(得分:1)
您可以使用间隔支持乘法的事实:
from sqlalchemy import Interval, literal
...
(func.date_trunc('days', func.timezone('utc', func.current_timestamp())) +
literal('1 hour').cast(Interval) * cls.daily_reset_time)
您也可以用算术替换CASE
表达式。这个想法是从当前时间中减去重置时间,如果尚未达到重置时间,则将其移至前一天,将其截断为日期精度,然后将时间加回来:
@previous_reset.expression
def previous_reset(cls):
utc_now = func.timezone('utc', func.current_timestamp())
hour_delta = literal('1 hour').cast(Interval) * cls.daily_reset_time
# The CASE expression is not needed even for the NULL handling, as the
# original would produce NULL in case `daily_reset_time` was NULL, as
# does the below expression.
return func.date_trunc('day', utc_now - hour_delta) + hour_delta