#python #sqlalchemy
#python #sqlalchemy
Вопрос:
У меня есть модель, где Edge
объект ассоциации соединяет Node
s и подразделяется на подклассы для создания разных типов Edge
s. Моя конечная цель — динамически создавать все поля подклассов в самом Edge
классе (или позже с помощью mixin).
Edge
имеет составной первичный ключ, состоящий из двух внешних ключей к Node
таблице и edge_type
поля, которое также действует как дискриминатор для подклассов.
Для этого мне нужно подключить подклассы с помощью a ForeignKeyConstraint
к составному первичному ключу Edge
класса. Теперь, чтобы создать это ForeignKeyConstraint
динамически, я определяю его с @declared_attr
помощью , но не могу ссылаться на edge_type
столбец, который должен быть унаследован из Edge
таблицы в подклассы, но я получаю следующие исключения:
File "/data/foo/venv/lib/python3.5/site-packages/sqlalchemy/util/_collections.py", line 194, in __getitem__
return self._data[key]
KeyError: 'edge_type'
During handling of the above exception, another exception occurred:
<snip>
sqlalchemy.exc.ArgumentError: Can't create ForeignKeyConstraint on table 'hierarchy': no column named 'edge_type' is present.
Моя модель выглядит так:
class Edge(HasTablename, Base):
from_node_id = Column(Integer, ForeignKey(Node.id), primary_key=True)
to_node_id = Column(Integer, ForeignKey(Node.id), primary_key=True)
from_node = relationship(Node, foreign_keys=from_node_id,
backref=backref('from_edges')
to_node = relationship(Node, foreign_keys=to_node_id,
backref=backref('to_edges')
edge_type = Column(String, primary_key=True)
@declared_attr
def __mapper_args__(cls):
if has_inherited_table(cls):
return {'polymorphic_identity': cls.__name__.lower()}
else:
return {'polymorphic_identity': cls.__name__.lower(),
'polymorphic_on': cls.edge_type}
@declared_attr
def __table_args__(cls):
if has_inherited_table(cls):
return (ForeignKeyConstraint(
['from_node_id', 'to_node_id', 'edge_type'],
[cls.__base__().__table__.c.from_node_id,
cls.__base__().__table__.c.to_node_id,
cls.__base__().__table__.c.edge_type]), )
class Hierarchy(Edge):
from_node_id = Column(Integer, primary_key=True)
to_node_id = Column(Integer, primary_key=True)
class History(Edge):
from_node_id = Column(Integer, primary_key=True)
to_node_id = Column(Integer, primary_key=True)
Это отлично работает, если я явно определяю edge_type = Column(String, primary_key=True)
в подклассах, но я не знаю, почему он не наследуется или не может быть доступен из ForeignKeyConstraint в @declared_attr
?
Комментарии:
1. «составной первичный ключ, состоящий из двух внешних ключей к таблице узлов и поля edge_type» , звучит как ужасная идея. Почему у вас нет обычного первичного ключа и уникального ограничения для них? Тогда класс, унаследованный от
Edge
, будет иметь простую ссылку на этот первичный ключ.2. Спасибо, да, вы совершенно правы, я действительно должен просто использовать UniqueConstraint!