I’m designing a database to house scientific test data, using sqlalchemy. I’ve hit a problem that I can’t seem to figure out.
In my test data, each Observation has a State (position, velocity, acceleration), and a State has an associated Time (time at which the state applies). So far, so good. I made a separate table for Times because I deal with different kinds of times, and I wanted to use a reference table to indicate what kind of time each time is (state time, observation time, etc). And the types of times I deal with might change, so normalizing in this way I think will let me add new kinds of times in the future, since they’re just rows in a reference table.
So far this part works (using declarative style):
class Observation(Base):
__tablename__ = 'tbl_observations'
id = Column(Integer, primary_key=True)
state_id = Column(Integer, ForeignKey('tbl_states.id'))
state = relationship('State', uselist=False)
class State(Base):
__tablename__ = 'tbl_states'
id = Column(Integer, primary_key=True)
time_id = Column(Integer, ForeignKey('tbl_times.id'))
time = relationship('Time', uselist=False)
class Time(Base):
__tablename__ = 'tbl_times'
id = Column(Integer, primary_key=True)
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
class TimeType(Base):
__tablename__ = 'ref_tbl_time_types'
id = Column(Integer, primary_key=True)
desc = Column(String)
The wrinkle is that observations themselves can have different kinds of times. When I try to create a one-to-many relationship between Observation and Time, I get a circular dependency error:
class Observation(Base):
__tablename__ = 'tbl_observations'
id = Column(Integer, primary_key=True)
state_id = Column(Integer, ForeignKey('tbl_states.id'))
state = relationship('State', uselist=False)
# Added this line:
times = relationship('Time')
class Time(Base):
__tablename__ = 'tbl_times'
id = Column(Integer, primary_key=True)
time_type_id = Column(Integer, ForeignKey('ref_tbl_time_types.id'))
time_type = relationship('TimeType', uselist=False)
time_value = Column(Float)
# Added this line:
observation_id = Column(Integer, ForeignKey('tbl_observations.id'))
I’m guessing this breaks because the original Observation -> State -> Time chain has a reference right back up to Observation.
Is there any way to fix this? Have I gotten my design all screwed up? Am I doing something wrong in sqlalchemy? I’m new to all of this so it could be any of the above. Any help you can give would be very much appreciated.
P.S. I tried doing what was recommended here: Trying to avoid a circular reference but either I did it wrong or it didn’t solve my particular problem.
The other answers here regarding reconsideration of your use case are valuable, and you should consider those. However, as far as SQLAlchemy is concerned, the circular dependency issue due to multiple FKs is solved by the use_alter/post_update combination, documented at http://docs.sqlalchemy.org/en/rel_0_7/orm/relationships.html#rows-that-point-to-themselves-mutually-dependent-rows . Here is the model using that: