2015-09-19 9 views
2

SQL Алхимия обрабатывает структуры смежности просто отлично, например. таблица самореферентных узел где внешний ключ node.parent_id относится к первичному ключу node.id.Отношения в SQLalchemy

У меня менее традиционная модель, где у узла есть два родителя (база данных генеалогии). В этом случае node.mat_id и node.pat_id относятся к материнским и родительским родительским узлам соответственно. SQL Алхимия в порядке с этим тоже:

mother = db.relationship("Node", 
    foreign_keys = "Node.mat_id", remote_side="Node.id") 
father = db.relationship("Node", 
    foreign_keys = "Node.pat_id", remote_side="Node.id") 

(с использованием декларативного).

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

offspring = db.relationship("Node", 
    foreign_keys = "Node.mat_id | Node.pat_id") 

Лучшее мне удалось это объявить mat_offspring и pat_offspring отношения отдельно и создать функцию-член отпрыска(), который возвращает соответствующий. Он работает, но кажется неэлегантным. Есть ли лучший и более обычный способ?

+2

Могу я предложить изменение схемы. Зачем вам нужны mat_id и pat_id отдельно? Вы можете использовать два столбца: ID и sex_flag (логическое значение). Это должно решить вашу проблему, так как теперь у вас есть 1 столбец для ссылки. Является ли это подходящим изменением в вашей ситуации? –

+0

Это уже существовавшая схема, используемая другим программным обеспечением, поэтому ее изменение вряд ли возможно, по крайней мере, в краткосрочной перспективе. Не могли бы вы немного расширить свое предложение? Возможно, стоит изучить его в какой-то момент в будущем. – Blackmyre

+0

А, я думаю, я понимаю, что вы имеете в виду: дополнительный стол для соединения с двумя (родительскими/дочерними) рядами на одного ребенка? Да, я думаю, это должно сработать и, возможно, было бы лучшим дизайном, если бы я начинал здесь. Я бы предпочел решение с учетом существующей схемы, но спасибо за предложение - я бы поднял его, но я здесь новый, поэтому у меня пока нет разрешения на это. – Blackmyre

ответ

1

Учитывая исходные ограничения схемы, вы оказались на правильном пути. Вместо foreign_keys вы бы передать условие соединения как primaryjoin:

class Node(Base): 
    __tablename__ = "node" 

    id = Column(Integer, primary_key=True) 
    mat_id = Column(ForeignKey(id)) 
    pat_id = Column(ForeignKey(id)) 

    mother = relationship("Node", foreign_keys=[mat_id], remote_side=id) 
    father = relationship("Node", foreign_keys=[pat_id], remote_side=id) 
    offspring = relationship("Node", 
     primaryjoin=or_(id == mat_id, id == pat_id), 
     viewonly=True) 

Обратите внимание, что из-за более сложным условие соединения отношения определяются как view only. Другими словами, вы не можете просто добавить потомство к узлу через него, потому что не можете сказать, родительский узел был отцом или матерью недавно добавленного потомства. В этом смысле ваши первоначальные отдельные материнские и отцовские отношения превосходны.

+0

Спасибо, я посмотрю на это. Этот проект был не более чем оправданием, чтобы сначала взглянуть на Python и SQLAlchemy и был оставлен пару лет назад. Как вы знаете из другого вопроса, хотя я теперь начал снова смотреть на него для другого проекта, поэтому техника может оказаться полезной. – Blackmyre

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