Вставить столбец на основе значения соответствующего столбца - PullRequest
0 голосов
/ 22 ноября 2018

Это похоже на настоящий вопрос новичка, но у меня возникают проблемы с поиском простого ответа.Я упростил это до простой схемы с простой моделью данных, представляющей отношение один ко многим:

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 голосов
/ 22 ноября 2018

Как отмечено в комментариях @SuperShoot, запрос на вставку может вычислить неиспользуемую емкость в базе данных без предварительной выборки.Явный конструктор, такой как показанный @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)

Хотя можно использовать клиентские выражения SQL в качестве значений по умолчанию,Я не уверен, как можно ссылаться на значения, которые будут вставлены в выражение, без использования контекстной функции по умолчанию , но это не совсем сработало: скалярный подзапрос не был встроенным, и SQLAlchemy пыталсявместо того, чтобы передавать его, используя заполнители.

Недостатком подхода __init__ является то, что вы не можете выполнять массовые вставки, которые бы обрабатывали неиспользованную емкость, используя таблицу, созданную для модели, как есть, но придется выполнять вручнуюзапрос, который делает то же самое.

Еще одна вещь, на которую следует обратить внимание, заключается в том, что до тех пор, пока не произойдет очистка, атрибут unusedCapacity нового объекта Event содержит объект выражения SQL, а не фактическое значение.Решение @tooTired более прозрачно в этом отношении, поскольку новый объект Event будет содержать числовое значение неиспользованной емкости с самого начала.

0 голосов
/ 22 ноября 2018

SQLAlchemy добавляет неявный конструктор ко всем классам модели, который принимает аргументы ключевых слов для всех своих столбцов и отношений.Вы можете переопределить это и передать kwargs без unusedCapacity и получить вместимость комнаты в конструкторе:

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)
...