Определение отношения таблицы закрытия SQL-алхимии - PullRequest
7 голосов
/ 07 января 2012

Я недавно начал работать с SQL Alchemy для проекта, который включает в себя лазание по районам и маршрутам. Области являются иерархическими в том смысле, что одна область может содержать несколько областей, которые, в свою очередь, могут содержать другие области. Маршрут напрямую связан с одной областью, но также связан с родителем этой области и т. Д.

Для реализации этого я выбрал закрывающую таблицу Билл Карвин . В реализации таблицы замыканий создается вторая таблица для хранения информации предка / потомка. При добавлении узла создается строка со ссылками на себя, а также строка для каждого предка в дереве.

Структура таблицы следующая (упрощенная):

-- area --
area_id
name

-- area_relationship --
ancestor
descendent

-- route --
route_id
area_id
name

Пример данных:

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

Аналогично, я могу запросить все маршруты в определенной области (включая области потомков) с помощью:

SELECT route.route_id, route.name
FROM area
    INNER JOIN area_relationship ON area.area_id = area_relationship.ancestor
    INNER JOIN route ON route.area_id = area_relationship.descendent
WHERE area.area_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. Однако, когда я пытаюсь использовать backref 'route' в DbArea, я получаю следующую ошибку:

sqlalchemy.exc.StatementError: Нет столбца route.area_id на маппере настроен Mapper | DbArea | area ... (первоначальная причина: UnmappedColumnError: Нет столбца route.area_id настроен на маппере Mapper | DbArea | area ...) 'ВЫБРАТЬ route.route_id AS route_route_id, route.area_id AS route_area_id, route.name AS route_name, route.created AS route_created \ nFROM route, area_relationship \ nWHERE% s = area_relationship.descendent AND route.area_id = area_relationship.ance {})]

Я предполагаю, что мне, вероятно, нужно что-то добавить в DbArea, чтобы установить взаимосвязь, но после экспериментов с некоторыми другими вариантами не удалось определить решение.

1 Ответ

6 голосов
/ 11 января 2012

После публикации в Google Alchemy Google Group и получения потрясающей помощи от Майкла Байера я пришел к следующему определению отношений областей в классе 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]) 

Ключ был в правильном определении соединений. Теперь я могу легко перейти из экземпляра маршрута и найти области в дереве предков или из области и найти все маршруты в дереве потомков.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...