使用 hybrid_property 对从其他列的值派生的时间列进行排序
Sorting time column derived from values of other columns using hybrid_property
我正在尝试构建一个活动预订系统,作为学习 python 和网络开发的副项目。下面是我的项目中实现的两个模型。 EventSlot 表示为特定 Event.
安排的时间段
型号
from app import db
from sqlalchemy import ForeignKey
from dateutil.parser import parse
from datetime import timedelta
from sqlalchemy.ext.hybrid import hybrid_property
class Event(db.Model):
event_id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, index=True, nullable=False)
duration = db.Column(db.Float, nullable=False)
price = db.Column(db.Float, nullable=False)
slots = db.relationship('EventSlot', cascade='all, delete', back_populates='event')
class EventSlot(db.Model):
slot_id = db.Column(db.Integer, primary_key=True)
event_date = db.Column(db.DateTime, nullable=False)
event_id = db.Column(db.Integer, ForeignKey('event.event_id'))
event = db.relationship('Event', back_populates='slots')
我为管理员用户提供了一个管理页面(Flask-Admin)来查看数据库记录。在 EventSlot 页面上,我包含了 'Start Time' 和 'End Time' 列,我想对其进行排序。我已将以下内容附加到 EventSlot 模型:
class EventSlot(db.Model):
#...
## working as intended ##
@hybrid_property
def start_time(self):
dt = parse(str(self.event_date))
return dt.time().strftime('%I:%M %p')
@start_time.expression
def start_time(cls):
return db.func.time(cls.event_date)
## DOES NOT WORK: can display derived time, but sorting is incorrect ##
@hybrid_property
def end_time(self):
rec = Event.query.filter(Event.event_id == self.event_id).first()
duration = rec.duration * 60
derived_time = self.event_date + timedelta(minutes=duration)
dt = parse(str(derived_time))
return dt.time().strftime('%I:%M %p')
@end_time.expression
def end_time(cls):
rec = Event.query.filter(Event.event_id == cls.event_id).first()
duration = '+' + str(int(rec.duration * 60)) + ' minutes'
return db.func.time(cls.event_date, duration)
从下图可以看出,我按'end time'排序的时候排序是错误的。它似乎仍在按开始时间排序。这可能是什么问题?
(诚然,我还是不懂hybrid_properties。我以为我在start_time工作时就明白了,但现在看来我还是不懂...... )
在 end_time
的表达式中,cls.event_id
表示一个列,而不是一个值,因此查询最终在 Event
和 EventSlot
之间执行隐式连接,并且选择该连接的第一个结果。这当然不是你想要的,而是对于 EventSlot
你想找出 SQL 中相关 Event
的持续时间。这似乎是使用相关标量子查询的好地方:
@end_time.expression
def end_time(cls):
# Get the duration of the related Event
ev_duration = Event.query.\
with_entities(Event.duration * 60).\
filter(Event.event_id == cls.event_id).\
as_scalar()
# This will form a string concatenation SQL expression, binding the strings as
# parameters to the query.
duration = '+' + ev_duration.cast(db.String) + ' minutes'
return db.func.time(cls.event_date, duration)
请注意,当在查询上下文中访问属性时,查询 不是 运行,而是成为父查询的一部分。
我正在尝试构建一个活动预订系统,作为学习 python 和网络开发的副项目。下面是我的项目中实现的两个模型。 EventSlot 表示为特定 Event.
安排的时间段型号
from app import db
from sqlalchemy import ForeignKey
from dateutil.parser import parse
from datetime import timedelta
from sqlalchemy.ext.hybrid import hybrid_property
class Event(db.Model):
event_id = db.Column(db.Integer, primary_key=True)
title = db.Column(db.String, index=True, nullable=False)
duration = db.Column(db.Float, nullable=False)
price = db.Column(db.Float, nullable=False)
slots = db.relationship('EventSlot', cascade='all, delete', back_populates='event')
class EventSlot(db.Model):
slot_id = db.Column(db.Integer, primary_key=True)
event_date = db.Column(db.DateTime, nullable=False)
event_id = db.Column(db.Integer, ForeignKey('event.event_id'))
event = db.relationship('Event', back_populates='slots')
我为管理员用户提供了一个管理页面(Flask-Admin)来查看数据库记录。在 EventSlot 页面上,我包含了 'Start Time' 和 'End Time' 列,我想对其进行排序。我已将以下内容附加到 EventSlot 模型:
class EventSlot(db.Model):
#...
## working as intended ##
@hybrid_property
def start_time(self):
dt = parse(str(self.event_date))
return dt.time().strftime('%I:%M %p')
@start_time.expression
def start_time(cls):
return db.func.time(cls.event_date)
## DOES NOT WORK: can display derived time, but sorting is incorrect ##
@hybrid_property
def end_time(self):
rec = Event.query.filter(Event.event_id == self.event_id).first()
duration = rec.duration * 60
derived_time = self.event_date + timedelta(minutes=duration)
dt = parse(str(derived_time))
return dt.time().strftime('%I:%M %p')
@end_time.expression
def end_time(cls):
rec = Event.query.filter(Event.event_id == cls.event_id).first()
duration = '+' + str(int(rec.duration * 60)) + ' minutes'
return db.func.time(cls.event_date, duration)
从下图可以看出,我按'end time'排序的时候排序是错误的。它似乎仍在按开始时间排序。这可能是什么问题?
(诚然,我还是不懂hybrid_properties。我以为我在start_time工作时就明白了,但现在看来我还是不懂...... )
在 end_time
的表达式中,cls.event_id
表示一个列,而不是一个值,因此查询最终在 Event
和 EventSlot
之间执行隐式连接,并且选择该连接的第一个结果。这当然不是你想要的,而是对于 EventSlot
你想找出 SQL 中相关 Event
的持续时间。这似乎是使用相关标量子查询的好地方:
@end_time.expression
def end_time(cls):
# Get the duration of the related Event
ev_duration = Event.query.\
with_entities(Event.duration * 60).\
filter(Event.event_id == cls.event_id).\
as_scalar()
# This will form a string concatenation SQL expression, binding the strings as
# parameters to the query.
duration = '+' + ev_duration.cast(db.String) + ' minutes'
return db.func.time(cls.event_date, duration)
请注意,当在查询上下文中访问属性时,查询 不是 运行,而是成为父查询的一部分。