我有一个像这样定义的模型类。我们的想法是,Person
将包含有关人员的一般信息,并提及它的子类和#34;:女人和男人作为父母。女人和男人将持有针对该性别的具体信息。
我使用Alembic生成迁移但我收到错误:
sqlalchemy.exc.AmbiguousForeignKeysError:无法确定' person'之间的联接和女人&#39 ;;表之间有多个外键约束关系。请指明' onclause'明确加入。
请注意,女性继承自人,因此也存在女性对人的引用。
我没有尝试过任何作品:
mother = relationship('Woman')
,认为SQL炼金术不理解这种关系mother_id = Column(Integer, ForeignKey('woman.id'), nullable=True)
mother = relationship('Woman', primaryjoin='Person.mother_id==Mother.id')
指定onclause是不可能的(或者我不知道怎么做),因为连接是自动生成的
class Person(Base):
__tablename__ = 'person'
id = Column(Integer, primary_key=True)
gender = Column(String(5))
name = Column(String(32), nullable=False)
surname = Column(String(32), nullable=False)
age = Column(Float, primary_key=True)
mother_id = Column(Integer, ForeignKey('woman.id'), nullable=True)
mother = relationship('Woman')
_mapper_args__ = {
'polymorphic_on': gender
}
class Woman(Person):
__tablename__ = 'woman'
__mapper_args__ = {
'polymorphic_identity': 'woman'
}
id = Column(Integer, ForeignKey('person.id'), primary_key=True)
完整追踪:
$ alembic revision --autogenerate -m "mother"
Traceback (most recent call last):
File "/Library/Frameworks/Python.framework/Versions/3.4/bin/alembic", line 11, in <module>
sys.exit(main())
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/config.py", line 479, in main
CommandLine(prog=prog).main(argv=argv)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/config.py", line 473, in main
self.run_cmd(cfg, options)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/config.py", line 456, in run_cmd
**dict((k, getattr(options, k)) for k in kwarg)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/command.py", line 117, in revision
script_directory.run_env()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/script/base.py", line 416, in run_env
util.load_python_file(self.dir, 'env.py')
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/util/pyfiles.py", line 93, in load_python_file
module = load_module_py(module_id, path)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/alembic/util/compat.py", line 68, in load_module_py
module_id, path).load_module(module_id)
File "<frozen importlib._bootstrap>", line 539, in _check_name_wrapper
File "<frozen importlib._bootstrap>", line 1614, in load_module
File "<frozen importlib._bootstrap>", line 596, in _load_module_shim
File "<frozen importlib._bootstrap>", line 1220, in load
File "<frozen importlib._bootstrap>", line 1200, in _load_unlocked
File "<frozen importlib._bootstrap>", line 1129, in _exec
File "<frozen importlib._bootstrap>", line 1471, in exec_module
File "<frozen importlib._bootstrap>", line 321, in _call_with_frames_removed
File "migrations/env.py", line 24, in <module>
import api.model
File "/Users/jakubt/Projects/hex/api/model.py", line 31, in <module>
class Woman(Person):
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/api.py", line 64, in __init__
_as_declarative(cls, classname, cls.__dict__)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 88, in _as_declarative
_MapperConfig.setup_mapping(cls, classname, dict_)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 103, in setup_mapping
cfg_cls(cls_, classname, dict_)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 135, in __init__
self._early_mapping()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 138, in _early_mapping
self.map()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/ext/declarative/base.py", line 530, in map
**self.mapper_args
File "<string>", line 2, in mapper
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/orm/mapper.py", line 671, in __init__
self._configure_inheritance()
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/orm/mapper.py", line 978, in _configure_inheritance
self.local_table)
File "<string>", line 2, in join_condition
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/sql/selectable.py", line 965, in _join_condition
a, b, constraints, consider_as_foreign_keys)
File "/Library/Frameworks/Python.framework/Versions/3.4/lib/python3.4/site-packages/sqlalchemy/sql/selectable.py", line 1055, in _joincond_trim_constraints
"join explicitly." % (a.description, b.description))
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 'person' and 'woman'; tables have more than one foreign key constraint relationship between them. Please specify the 'onclause' of this join explicitly.
答案 0 :(得分:0)
我在这里看到的问题是你将外键引用到外键。
mother_id -> foreign_key(woman.id)
woman.id -> foreign_key(person.id)
并创建循环依赖。您无法在任何SQL方言的任何单个创建语句中创建该依赖项。您首先需要创建person
表,然后创建woman
表,然后从第一个表到第二个表添加foreign key (mother_id)
(请注意,您不能先创建女性表,因为它有人员表的外键)。
我不认为alembic足够聪明,而且我认为你想要实现的目标并不是一件好事。
以下是我的建议:
woman.id
对于一条记录总是与person.id
具有相同的值,因此第一个外键应该引用person表而不是母表。
更改mother_id
和mother
的定义:
mother_id = Column(Integer, ForeignKey('person.id'), nullable=True)
mother = relationship('Person', primaryjoin='Person.mother_id==Person.id')
提示:如果您只是存储id(只需从第二课中删除__tablename__
),则您不需要第二个表格
在添加母亲/父亲时检查代码中的性别。