使用 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 表示一个列,而不是一个值,因此查询最终在 EventEventSlot 之间执行隐式连接,并且选择该连接的第一个结果。这当然不是你想要的,而是对于 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)

请注意,当在查询上下文中访问属性时,查询 不是 运行,而是成为父查询的一部分。