根据相关列值插入列

时间:2018-11-21 22:11:32

标签: python sqlalchemy flask-sqlalchemy

这似乎是一个真正的初学者问题,但是我很难找到一个简单的答案。我已使用表示一对多关系的简单数据模型将其简化为基本内容:

class Room(db.Model):
    __tablename__ = 'rooms'
    id        = db.Column(db.Integer, primary_key=True)
    name      = db.Column(db.String(128), unique=True)
    capacity  = db.Column(db.Integer)
    events    = db.relationship('Event', backref='room')


class Event(db.Model):
    __tablename__ = 'counts'
    id               = db.Column(db.Integer, primary_key=True)
    unusedCapacity   = db.Column(db.Integer)
    attendance       = db.Column(db.Integer)
    room_id          = db.Column(db.Integer, db.ForeignKey('rooms.id'))

Event.unusedCapacity的计算方式为Room.capacity - Event.attendance,但是我需要将值存储在列中-Room.capacity可能会随时间而变化,但是Event.unusedCapacity需要反映实际值事件发生时未使用的容量。

我当前正在查询会议室,然后创建活动:

room = Room.query.get(room_id) # using Flask sqlAlchemy
event = event(unusedCapacity = room.capacity - attendance, ...etc) 

我的问题是:有没有一种更有效的方法来一步一步做到这一点?

2 个答案:

答案 0 :(得分:2)

如@SuperShoot的注释中所述,对insert的查询可以计算数据库中未使用的容量,而不必先获取。如@tooTired所示的显式构造函数可以将标量子查询传递为unusedCapacity

class Event(db.Model):
    ...
    def __init__(self, **kwgs):
        if 'unusedCapacity' not in kwgs:
            kwgs['unusedCapacity'] = \
                db.select([Room.capacity - kwgs['attendance']]).\
                where(Room.id == kwgs['room_id']).\
                as_scalar()
        super().__init__(**kwgs)

虽然可以使用client-invoked SQL expressions作为默认值,但是我不确定在不使用context-sensitive default function的情况下如何可以引用要在表达式中插入的值,但这并不完全有效出:没有内联标量子查询,SQLAlchemy尝试使用占位符传递它。

__init__方法的缺点是,您无法使用为模型创建的表按原样执行处理未使用容量的批量插入,而必须执行相同操作的手动查询。

要注意的另一件事是,在刷新发生之前,新unusedCapacity对象的Event属性将保留SQL表达式对象,而不是实际值。在这方面,@ tooTired的解决方案更加透明,因为新的Event对象将保存get go中未使用容量的数值。

答案 1 :(得分:1)

SQLAlchemy向所有模型类添加一个隐式构造函数,该构造函数为其所有列和关系接受关键字参数。您可以覆盖此内容,并传递不带未使用容量的kwarg,并在构造函数中获取房间容量:

class Event(db.Model):
    # ...
    #kwargs without unusedCapacity
    def __init__(**kwargs):
        room = Room.query.get(kwargs.get(room_id))
        super(Event, self).__init__(unusedCapacity = room.capacity - kwargs.get(attendance), **kwargs)


#Create new event normally
event = Event(id = 1, attendance = 1, room_id = 1)