Недавно я начал работать с 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, чтобы установить отношения, но после экспериментировать с некоторыми разными опциями не удалось определить решение.