SQLAlchemy 'on_conflict_do_update' не обновляется - PullRequest
0 голосов
/ 23 октября 2018

У меня есть следующий код, который я хотел бы сделать upsert:

def add_electricity_reading(
    *, period_usage, period_started_at, is_estimated, customer_pk
):
    from sqlalchemy.dialects.postgresql import insert

    values = dict(
        customer_pk=customer_pk,
        period_usage=period_usage,
        period_started_at=period_started_at,
        is_estimated=is_estimated,
    )
    insert_stmt = insert(ElectricityMeterReading).values(**values)
    do_update_stmt = insert_stmt.on_conflict_do_update(
        constraint=ElectricityMeterReading.__table_args__[0].name,
        set_=dict(
            period_usage=period_usage,
            period_started_at=period_started_at,
            is_estimated=is_estimated,
        )
    )
    conn = DBSession.connection()
    conn.execute(do_update_stmt)

    return DBSession.query(ElectricityMeterReading).filter_by(**dict(
        period_usage=period_usage,
        period_started_at=period_started_at,
        customer_pk=customer_pk,
        is_estimated=is_estimated,
    )).one()

 def test_updates_existing_record_for_started_at_if_already_exists():
    started_at = datetime.now(timezone.utc)
    existing = add_electricity_reading(
        period_usage=0.102,
        customer_pk=customer.pk,
        period_started_at=started_at,
        is_estimated=True,
    )
    started_at = existing.period_started_at
    reading = add_electricity_reading(
        period_usage=0.200,
        customer_pk=customer.pk,
        period_started_at=started_at,
        is_estimated=True,
    )

    # existing record was updated
    assert reading.period_usage == 0.200
    assert reading.id == existing.id

В моем тесте, когда я добавляю существующую запись с period_usage=0.102, а затем снова выполнить запрос, но изменить на period_usage=0.2.Когда последний запрос внизу возвращает запись, period_usage по-прежнему равен 0.102.

Есть идеи, почему это может происходить?

1 Ответ

0 голосов
/ 23 октября 2018

Это поведение объясняется в разделе «Основы сеанса» в разделе «Что делает сеанс?» Сеанс содержит ссылки на объекты, которые он загрузил, в структуре, называемой карта идентификации ,и таким образом гарантирует, что в течение времени жизни сеанса существует только 1 уникальный объект на значение первичного ключа.Вы можете проверить это с помощью следующего утверждения в своем собственном коде:

assert existing is reading

Core операторы вставки (или обновления), которые вы выполняете, не синхронизируют сеанс с изменениями, принимающимипоместите в базу данных, как, например, Query.update().Чтобы получить новые значения, вы можете expire загруженное ORM состояние уникального объекта:

DBSession.expire(existing)  # or reading, does not matter

# existing record was updated
assert reading.period_usage == 0.200
assert reading.id == existing.id
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...