2012-01-07 3 views
6

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

Для реализации этого я решил использовать closure table ala Bill Karwin. В реализации таблицы закрытия создается вторая таблица для хранения информации о предках/потомках. Строка саморегуляции создается при добавлении узла, а также строка для каждого предка в дереве.

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

-- 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 алхимии я создал отношения и две таблицы для обработки этих отношений:

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 'routes' в DbArea, я получаю следующую ошибку:

sqlalchemy.exc.StatementError: Никакой столбец route.area_id не настроен на mapper Mapper | DbArea | area ... (original причина: UnmappedColumnError: Нет столбца route.area_id настроен на mapper Mapper | DbArea | area ...) 'SELECT route.route_id AS route_route_id, route.area_id AS route_area_id, route.name AS имя_маршрута, route.created AS route_created \ nFROM route , area_relationship \ nWHERE% s = area_relationship.descendent AND route.area_id = area_relationship.ancestor '[immutabledict ({})]

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

ответ

6

После размещения в SQL Алхимия группы Google и получать некоторые awesome help from Michael Bayer, я пришел к следующему определению отношений площадей в классе 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]) 

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

Смежные вопросы