引用同一个表的一列中的多个外键

时间:2014-01-08 18:22:48

标签: python sqlite sqlalchemy

我有一个名为“Subtests”的表和一个名为“TestSteps”的表(在使用SQLalchemy的sqlite数据库中),我想允许在多个子测试之间共享测试步骤。这需要在同一“TestStep”表列中存储对子测试ID的多个引用。这可能吗?基本上它是“TestSteps”表中的外键列表。如何建立这种关系?我在SQLAlchemy文档中看到了一些对外键列表的引用,但没有找到具体的例子。

目前,当我尝试向TestStep外键列(“subTestID”)添加第二个引用时,它会覆盖原始条目。我想将多个条目存储为外键列表。

以下是表格的初始化方式:

class SubTest(Base):

    __tablename__ = "SubTests"
    id = Column(Integer, primary_key=True)
    testSteps = relationship("TestStep", backref = "subTest", order_by=TestStep.testStepNumber)


class TestStep(Base):

    __tablename__ = "TestSteps"
    id = Column(Integer, primary_key = True)
    subTestID = Column(Integer, ForeignKey("SubTests.id"))

提前感谢所有人! 丹尼尔

1 个答案:

答案 0 :(得分:1)

对于您拥有的当前结构,这是不可能的。您模型当前实现 One To Many类型relationship

您需要的是Many To Many
您应该阅读上面链接的文档,但重点是:您需要有一个关系表来保存关系对。下面的代码应根据您的模型显示:

teststep_subtest = Table('teststep_subtest',
    Base.metadata,
    Column('subtest_id', Integer, ForeignKey('SubTests.id'), primary_key=True),
    Column('teststep_id', Integer, ForeignKey('TestSteps.id'), primary_key=True),
    )

class TestStep(Base):
    __tablename__ = "TestSteps"
    id = Column(Integer, primary_key = True)
    tag = Column(String) # @note: just for tests
    #subTestID = Column(Integer, ForeignKey("SubTests.id")) # @note: removed
    testStepNumber = Column(Integer)

class SubTest(Base):
    __tablename__ = "SubTests"
    id = Column(Integer, primary_key=True)
    tag = Column(String) # @note: just for tests
    #testSteps = relationship("TestStep", backref = "subTest", order_by=TestStep.testStepNumber)
    testSteps = relationship('TestStep',
            secondary=teststep_subtest,
            backref='subTests',
            order_by=TestStep.testStepNumber,
            )

以下示例测试代码:

ts1 = TestStep(tag="start", testStepNumber=0)
ts2 = TestStep(tag="do-something-cool")
ts3 = TestStep(tag="do-something-groovy")
ts4 = TestStep(tag="do-nothing")
ts5 = TestStep(tag="finish", testStepNumber=9)


st1 = SubTest(tag="sub-test-01", testSteps=[ts5, ts2, ts3, ts4, ts1])
st2 = SubTest(tag="sub-test-02", testSteps=[ts5, ts3, ts1])
st3 = SubTest(tag="sub-test-03-nosteps")
session.add_all([ts1, ts2, ts3, ts4, ts5, st1, st2, st3])
session.commit()
session.expunge_all()

# query test
print '-' * 80
#engine.echo = False
for _st in session.query(SubTest).all():
    print "SubTest:", _st.tag
    for _ts in _st.testSteps:
        print "  ", _ts.testStepNumber, _ts.tag

应该产生这样的输出:

SubTest: sub-test-01
   None do-something-cool
   None do-something-groovy
   None do-nothing
   0 start
   9 finish
SubTest: sub-test-02
   None do-something-groovy
   0 start
   9 finish
SubTest: sub-test-03-nosteps

我认为以上内容应该为您提供多对多的简介。但是,我怀疑它对你来说不够好,因为我猜每个testStepNumber TestStep可能需要不同。在这种情况下,您可以将此字段移动到关系表,在此阶段您可以转到另一个解决方案:

(可选)下一步:Association Object
正如您将从Association Object的文档中看到的,如果您确实需要在关联级别存储更多数据,那么它将是一个结构。