SQLAlchemy: Как обработать список смежности с внешним ключом к другой таблице? - PullRequest
0 голосов
/ 01 ноября 2019

Давайте рассмотрим следующий минимальный пример:

  • таблица измерений с идентификатором и именем.
  • таблица моделирования с идентификатором и именем. Кроме того, существует внешний ключ, ссылающийся на идентификатор измерения, на котором основано моделирование, и внешний ключ, ссылающийся на другое моделирование, на котором основано моделирование.

Минимальный рабочий пример кода, который я придумал, следующий:

from sqlalchemy import create_engine
from sqlalchemy.ext.declarative import declarative_base
from sqlalchemy import Column, ForeignKey, Integer, String
from sqlalchemy.orm import sessionmaker, scoped_session, relationship

engine = create_engine('postgresql://postgres:12345@localhost:5432/Example')

Session = scoped_session(sessionmaker(bind=engine))

Base = declarative_base()

class Measurement(Base):
    __tablename__ = 'measurement'

    id = Column(Integer, primary_key=True)
    name = Column(String)

    simulation = relationship('Simulation', back_populates='measurement', uselist=False)


class Simulation(Base):
    __tablename__ = 'simulation'

    id = Column(Integer, primary_key=True)
    name = Column(String)
    measurement_id = Column(Integer, ForeignKey('measurement.id', onupdate='CASCADE', ondelete='CASCADE'))
    parent_simulation_id = Column(Integer, ForeignKey('simulation.id'), index=True)

    measurement = relationship('Measurement', back_populates='simulation')
    parent_simulation = relationship('Simulation', remote_side=id, backref='child_simulation')

Base.metadata.create_all(engine)

Но теперь у меня странное поведение при использовании кода. С первым кодом тестирования все прошло хорошо:

sess = Session()

measurement = Measurement(name='Measurement_1')
sess.add(measurement)
sess.commit()

simulation1 = Simulation(name='Simulation_1', measurement=measurement, parent_simulation=None)
simulation2 = Simulation(name='Simulation_1.1', measurement=measurement, parent_simulation=simulation1)

sess.add_all((simulation2, simulation1))
sess.commit()

Как и ожидалось, получится следующий вывод:

 id |      name      | measurement_id | parent_simulation_id
----+----------------+----------------+----------------------
  1 | Simulation_1   |              1 |
  2 | Simulation_1.1 |              1 |                    1

Но тогда, если я изменю код тестирования, произойдет первое моделированиесбрасывается перед инициализацией второго ...

sess = Session()

measurement = Measurement(name='Measurement_1')
sess.add(measurement)
sess.commit()

simulation1 = Simulation(name='Simulation_1', measurement=measurement, parent_simulation=None)
sess.add_all((simulation1, ))
sess.flush()

simulation2 = Simulation(name='Simulation_1.1', measurement=measurement, parent_simulation=simulation1)
sess.add_all((simulation2, ))
sess.commit()

... результат уже не тот, что ожидалось:

 id |      name      | measurement_id | parent_simulation_id
----+----------------+----------------+----------------------
  1 | Simulation_1   |                |
  2 | Simulation_1.1 |              1 |                    1

Что я делаю не так? Почему measurement_id первого симуляции пропадает, когда я вхожу во второй?

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