SQLAlchemy使用反射建模复杂关系

时间:2012-07-09 17:09:36

标签: python sqlalchemy

我正在查询由第三方维护的专有数据库。数据库有许多表,每个表都有大量的字段。

我的问题涉及三个感兴趣的表格,树,网站和仪表。

树表描述了简单树结构中的节点。与其他数据一起,它有一个引用其自己的主键的外键。它还有一个Object_Type字段和一个Object_ID字段。 Site和Meter表各有许多字段。

树节点具有一对一的关系, 是一个米一个站点。如果Object_Type字段为1,则Object_ID字段引用Site表中的主键。如果是2那么它指的是Meter表中的主键。

遵循此示例https://bitbucket.org/sqlalchemy/sqlalchemy/src/408388e5faf4/examples/declarative_reflection/declarative_reflection.py

我正在使用反射来加载像这样的表结构

Base = declarative_base(cls=DeclarativeReflectedBase)

class Meter(Base):
    __tablename__ = 'Meter'

class Site(Base):
    __tablename__ = 'Site'

class Tree(Base):
    __tablename__ = 'Tree'
    Parent_Node_ID = Column(Integer, ForeignKey('Tree.Node_ID'))
    Node_ID = Column(Integer, primary_key=True)
    children = relationship("Tree", backref=backref('parent', remote_side=[Node_ID]))

Base.prepare(engine)

我已经包含了自我指涉关系并且完美无缺。如何使用Object_ID作为外键添加两个关系,并对Object_Type字段进行适当的检查?

2 个答案:

答案 0 :(得分:2)

首先注意反思。我发现自己好好不依赖于反思。

  1. 您不需要有效的数据库连接来加载/使用您的代码
  2. 它违反了python指南,显式优于隐式。如果你看一下代码,你最好元素(列等),而不是在你的视野之外神奇地创建它们。
  3. 这意味着更多代码,但更易于维护。

    我建议的原因至少部分是我在帖子中看不到架构。

    如果您在代码中创建表和类而不是依赖于反射,那么您可以更好地控制映射。

    在这种情况下,您希望使用多态映射

    1. 按上述方法创建一个TreeNode类。
    2. 将SiteNode和MeterNode创建为子类
    3. 您的代码将包含以下内容:

      mapper(TreeNode,tree_table,polymorphic_on=tree_table.c.object_type)
      mapper(SiteNode, site_table,inherits=TreeNode,
                       inherit_condition=site_table.c.node_id==tree_table.c.node_id,
                       polymorphic_identity=1)
      

      希望这有帮助。

答案 1 :(得分:1)

for tree.object_id是一个可以引用Site或Meter的外键,你可以让Site和Meter从公共基表下降,即连接表继承,或者映射到相同的表,即单表继承,或者有人说将Tree映射到两个不同的表以及公共基表。最后一个建议很好地认为TreeNode已经有一个“类型”字段。

最简单的替代方法是直接在TreeNode上使用两个外键 - site_id和meter_id,以及两个关系,“meter”和“site”;然后使用Python @property返回一个或另一个:

class TreeNode(Base):
   # ...

   @property
   def object(self):
       return self.meter or self.site