Редактировать объект orm на основе запроса с полями меток - PullRequest
2 голосов
/ 19 августа 2011

Время больше раздвигать границы sqlalchemy.Это не перестает удивлять!

Справочная информация

У меня есть таблица для устройств и таблица для записи физических связей между ними.

class Device(Base):
    __tablename__ =  "device"
    device_id = sa.Column(sa.Integer, primary_key=True)
    name = sa.Column(sa.String(255), nullable=False)


class PhysicalLink(Base):
    __tablename__ =  "physical_link"
    physical_links_id = sa.Column(sa.Integer, primary_key=True)

    device_id_1 = sa.Column(sa.types.Integer, sa.ForeignKey(Device.device_id), nullable=False)
    device_port_1 = sa.Column(sa.String(255), nullable=False)

    device_id_2 = sa.Column(sa.types.Integer, sa.ForeignKey(Device.device_id), nullable=False)
    device_port_2 = sa.Column(sa.String(255), nullable=False)

    cable_number = sa.Column(sa.String(255), nullable=False)

Когда я имею дело с физическими ссылками для известного устройства,Я не хочу, чтобы всегда были операторы if, чтобы решить, должен ли я смотреть на device_ [id | port] _ 1 или 2, поэтому я сделал:

physical_links_table = PhysicalLinks.__table__
physical_links_ua = union_all(
    select((
        physical_links_table.c.physical_links_id,
        label('this_device_id', physical_links_table.c.device_id_1),
        label('this_device_port', physical_links_table.c.device_port_1),
        label('other_device_id', physical_links_table.c.device_id_2),
        label('other_device_port', physical_links_table.c.device_port_2),
        physical_links_table.c.cable_number,
        ),),
    select((
        physical_links_table.c.physical_links_id,
        label('this_device_id', physical_links_table.c.device_id_2),
        label('this_device_port', physical_links_table.c.device_port_2),
        label('other_device_id', physical_links_table.c.device_id_1),
        label('other_device_port', physical_links_table.c.device_port_1),
        physical_links_table.c.cable_number,
        ),),
    ).alias('physical_links_ua')

class PhysicalLinksDir(object):
    pass


physical_links_dir_mapper = orm.mapper(PhysicalLinksDir, physical_links_ua)
physical_links_dir_mapper.add_property(
    'this_device', orm.relation(Device, primaryjoin=(PhysicalLinksDir.this_device_id == Device.device_id)))
physical_links_dir_mapper.add_property(
    'other_device', orm.relation(Device, primaryjoin=(PhysicalLinksDir.other_device_id == Device.device_id)))

Это позволяет мне сделать:

physical_links = (db_session
    .query(PhysicalLinksDir)
    .filter(PhysicalLinksDir.this_device_id = my_device.device_id)
    .options(joinedload('other_device')))
for pl in physical_links:
    print pl.other_device

(Я помню, что сказал вам, что я думаю, что sqlalchmey качается!)

Вопрос

Что мне нужно сделать, чтобы можно было изменить PhysicalLinksDirатрибуты экземпляра, и сможете ли передать их обратно в БД?

1 Ответ

0 голосов
/ 24 августа 2011

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

Кроме того, существует проблема с типом отображения, который у вас есть. Вы ожидаете, что у вас будет 2 строки PhysicalLinksDir для каждой строки PhysicalLink (по одной на каждую сторону), но если вы попробуете это, вы увидите, что это не так. Причина этого в том, что первый столбец (physical_links_id) считается primary_key, поэтому Объект запроса отбрасывает второй объект с тем же значением.
Чтобы это исправить, вам нужно настроить primary_key вручную. Предполагая, что может быть только один соединение между двумя различными устройствами, решение ниже поможет. Возможно, вам придется расширить его, чтобы включить port:

physical_links_dir_mapper = orm.mapper(PhysicalLinksDir, physical_links_ua,
    # @note: add this
    primary_key=[physical_links_ua.c.physical_links_id, physical_links_ua.c.this_device_id],
    )

УДАЛИТЬ : Теперь, чтобы поддержать delete, все, что вам нужно сделать, это добавить связь между вашим PLD и фактическим PhysicalLink, а session.delete(my_PLD); session.commit() также удалит PhysicalLink это представляет:

physical_links_dir_mapper.add_property(
    'physical_link', orm.relation(PhysicalLink, primaryjoin=(
                              PhysicalLinksDir.physical_links_id == PhysicalLink.physical_links_id),
                              foreign_keys=[PhysicalLinksDir.physical_links_id]
    ))

Но на самом деле удаление может работать из коробки, поскольку модель мягко связана с таблицей physical_link.

INSERT : Ну, это легко сделать с помощью объекта PhysicalLink напрямую, так что я бы просто сохранил его таким образом.

ОБНОВЛЕНИЕ : Вы, вероятно, могли бы достичь этого с помощью Сеансовых событий , но самый простой способ - это просто обернуть все атрибуты в @property, который делегировал бы изменение на соответствующий объект.

ВАЖНО : я все еще думаю, что этот способ работы не очень хорош, потому что ссылки не обновляются автоматически и ваша память UnitOfWork может быть несовместимой.


Если также было бы полезно понять, почему вы думаете, этот способ работы с вашими объектами будет лучше? Каковы случаи использования этого приложения?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...