简体   繁体   English

SQLAlchemy:如何处理与其他表的外键邻接表?

[英]SQLAlchemy: How to handle adjacency list with foreign key to other table?

Let us consider the following minimal example:让我们考虑以下最小示例:

  • measurement table with an id and a name.带有 id 和名称的测量表。
  • simulation table with an id and a name.带有 id 和名称的模拟表。 Additionaly there is a foreign key referencing the id of the measurement the simulation is based on and a foreign key referencing an other simulation the simulation is based on.此外,还有一个外键引用模拟所基于的测量的 id,以及一个外键引用模拟所基于的其他模拟。

A minimal working example of the code I came up with is the following:我想出的代码的最小工作示例如下:

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)

But now I have a strange behaviour using the code.但是现在我使用代码有一个奇怪的行为。 With the first testing code, everything went well:有了第一个测试代码,一切都很顺利:

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

As expected, the output is the following:正如所料,output 如下:

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

But then, if I change the testing code so the first simulation gets flushed before the second gets initialized...但是,如果我更改测试代码,以便在第二个模拟被初始化之前刷新第一个模拟......

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

...the outcome is not as expected anymore: ...结果不再像预期的那样:

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

What am I doing wrong?我究竟做错了什么? Why is the measurement_id of the first simulation gone once I enter the second one?为什么我进入第二个模拟后第一个模拟的measurement_id消失了?

I am not sure if I completly understand your data model, but for a Simulation referencing to none or one Measurement, you don't need the我不确定我是否完全理解您的数据 model,但是对于没有引用或引用一个测量的模拟,您不需要

measurement = relationship('Measurement', back_populates='simulation')

in the Simulation class, do you?在模拟class,你呢? Try to remove this relationship.尝试消除这种关系。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM