Python SQL Alchemy闭包表关系定义

Python SQL Alchemy闭包表关系定义,python,sqlalchemy,Python,Sqlalchemy,我最近开始为一个涉及攀登区域和路线的项目使用SQL Alchemy。区域是分层的,因为单个区域可能包含多个区域,而多个区域又可能包含其他区域。路线直接与单个区域关联,但也与该区域的父区域关联,等等 为了实现这一点,我选择使用。在闭包表实现中,创建第二个表来存储祖先/后代信息。添加节点时将创建自引用行,并为树中的每个祖先创建一行 表格结构如下(简化): 样本数据: -- area -- 1, New River Gorge 2, Kaymoor 3, South Nuttall 4, Meadow

我最近开始为一个涉及攀登区域和路线的项目使用SQL Alchemy。区域是分层的,因为单个区域可能包含多个区域,而多个区域又可能包含其他区域。路线直接与单个区域关联,但也与该区域的父区域关联,等等

为了实现这一点,我选择使用。在闭包表实现中,创建第二个表来存储祖先/后代信息。添加节点时将创建自引用行,并为树中的每个祖先创建一行

表格结构如下(简化):

样本数据:

-- area --
1, New River Gorge
2, Kaymoor
3, South Nuttall
4, Meadow River Gorge

-- area_relationship (ancestor, descendent) --
1, 1 (self-referencing)
2, 2 (self-referencing)
1, 2 (Kaymoor is w/i New River Gorge)
3, 3 (self-referencing)
1, 3 (South Nutall is w/i New River Gorge)
4, 4 (self-referencing)

-- route (route_id, area_id, name)
1, 2, Leave it to Jesus
2, 2, Green Piece
3, 4, Fancy Pants
要查询给定路线(树上)的所有区域,我可以执行:

SELECT area.area_id, area.name
FROM route 
    INNER JOIN area_relationship ON route.area_id = area_relationship.descendent
    INNER JOIN area ON area.area_id = area_relationship.ancestor
WHERE route.route_id = 1
类似地,我可以通过以下方式查询特定区域(包括子区域)中的所有路线:

在SQL Alchemy中,我创建了一个关系和两个表来处理这些关系:

area_relationship_table = Table('area_relationship', Base.metadata,
  Column('ancestor', Integer, ForeignKey('area.area_id')),
  Column('descendent', Integer, ForeignKey('area.area_id'))
)
DbArea类-

class DbArea(Base):

    __tablename__ = 'area'

    area_id = Column(Integer, primary_key = True)
    name = Column(VARCHAR(50))
    created = Column(DATETIME)

    area_relationship_table.c.ancestor])

    descendents = relationship('DbArea', backref = 'ancestors',
        secondary =  area_relationship_table,
        primaryjoin = area_id == area_relationship_table.c.ancestor,
        secondaryjoin = area_id == area_relationship_table.c.descendent)
DbRoute类-

    class DbRoute(Base):

        __tablename__ = 'route'

        route_id = Column(Integer, primary_key = True)
        area_id = Column(Integer, ForeignKey('area.area_id'))
        name = Column(VARCHAR(50))
        created = Column(DATETIME)

        area = relationship("DbArea")

        areas = relationship('DbArea', backref = 'routes',
            secondary = area_relationship_table,
            primaryjoin = area_id == area_relationship_table.c.ancestor,
            secondaryjoin = area_id == area_relationship_table.c.descendent,
            foreign_keys=[area_relationship_table.c.ancestor,
            area_relationship_table.c.descendent])
目前,我可以使用DbRoute中的areas关系从单个路由确定区域。但是,当我尝试在dbrea中使用backref“routes”时,会出现以下错误:

sqlalchemy.exc.StatementError:映射器映射器| Dbrea | area上未配置列路由.area_id。。。(原始原因:未映射列错误:没有在映射器映射器上配置列route.area|id,| Dbrea | area | area…“选择route.route|id作为route_route_id,route.area_id作为route_area_id,route.name作为route_名称,route.created作为route_从route创建的路由”,area\u关系\n此处%s=area\u关系。后代和路由。area\u id=area\u关系。祖先'[immutabledict({})]


我猜我可能需要向DBrea添加一些东西来建立关系,但在尝试了一些不同的选项后,无法确定解决方案。

在发布到SQL Alchemy Google组并收到一些后,我在DbRoute类中得出了区域关系的以下定义

areas = relationship('DbArea',
    backref = backref('routes', order_by = 'DbRoute.name'),
    secondary = area_relationship_table,
    primaryjoin = area_id == area_relationship_table.c.descendent,
    secondaryjoin = DbArea.area_id == area_relationship_table.c.ancestor,
    innerjoin = True, order_by = DbArea.name,
    foreign_keys =
       [area_relationship_table.c.ancestor,
            area_relationship_table.c.descendent]) 
关键在于正确定义连接。现在我可以很容易地从一个路由实例中找到祖先树中的区域,或者从一个区域中找到后代树中的所有路由

    class DbRoute(Base):

        __tablename__ = 'route'

        route_id = Column(Integer, primary_key = True)
        area_id = Column(Integer, ForeignKey('area.area_id'))
        name = Column(VARCHAR(50))
        created = Column(DATETIME)

        area = relationship("DbArea")

        areas = relationship('DbArea', backref = 'routes',
            secondary = area_relationship_table,
            primaryjoin = area_id == area_relationship_table.c.ancestor,
            secondaryjoin = area_id == area_relationship_table.c.descendent,
            foreign_keys=[area_relationship_table.c.ancestor,
            area_relationship_table.c.descendent])
areas = relationship('DbArea',
    backref = backref('routes', order_by = 'DbRoute.name'),
    secondary = area_relationship_table,
    primaryjoin = area_id == area_relationship_table.c.descendent,
    secondaryjoin = DbArea.area_id == area_relationship_table.c.ancestor,
    innerjoin = True, order_by = DbArea.name,
    foreign_keys =
       [area_relationship_table.c.ancestor,
            area_relationship_table.c.descendent])