【问题标题】:SQLAlchemy: How do I create a 1:n relationship? [duplicate]SQLAlchemy:如何创建 1:n 关系? [复制]
【发布时间】:2018-01-31 01:54:01
【问题描述】:

我即将使用 SQLAlchey 创建某种 1:n-realtionship。

我给你带来了两张照片,你可以看看这是怎么回事。首先,您将看到 EER 模型的图片。在这个 EER 模型中,我在 person 表和 family 表之间创建了 1:n 的关系。任何人都存储在 person 表中。我们都知道,人们可以彼此建立关系(母亲、父亲、女儿、儿子、堂兄、堂兄、侄子等)。为此,我设置了 family 表。

为了始终起到示范作用,我在表格中填满了虚构数据。查看家庭表,我们在第一列中看到中心人物,即 Hans Schmidt(ID 为 1)。在 Family 表中,以下人员通过外键保存:Kurt Schmidt(儿子)、Gerda Schmidt(妻子)、Gisela Schmidt(Hans 的母亲)和 Julia Schmidt(女儿)。我想指出汉斯·施密特的关系。

在我的源代码中,我已经将这个 ORM 模型映射如下:

class FAMILY(Base):

    __tablename__ = "family"

    id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
    status = Column(String(255), nullable=False)

    person_id = Column(Integer, ForeignKey('person.id'))
    person = relationship("PERSON", backref='family', lazy='dynamic')

    family_person_id = Column(Integer, ForeignKey('person.id'))
    family_person = relationship("PERSON", backref='family', lazy='dynamic')


class PERSON(Base):

    __tablename__ = "person"

    id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
    nickname = Column(String(255))
    alias_name  = Column(String (255))
    name_normally_used = Column(String(50), nullable=False)
    first_middle_name = Column(String(255))
    last_name = Column(String(100))

创建模型时,SQLAlchemy 不会导致任何问题(回显是真的,所以我可以跟踪它没有问题。)。但是,当我启动用户界面时,SQLAlchemy 会引发异常,您可以在其中管理人员的数据。

Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 140, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 205, in select_all
for record in dict_store_session_query[category]():
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 191, in <lambda>
'person_gender': lambda: self._session.query(PERSON_GENDER),
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1362, in query
return self._query_cls(entities, self, **kwargs)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 139, in __init__
self._set_entities(entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 150, in _set_entities
self._set_entity_selectables(self._entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 180, in _set_entity_selectables
ent.setup_entity(*d[entity])
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 3585, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File "C:\Python27\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1948, in _with_polymorphic_mappers
configure_mappers()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 2869, in configure_mappers
raise e
InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers. Triggering mapper: 'Mapper|FAMILY|family'. Original exception was: Could not determine join condition between parent/child tables on relationship FAMILY.person - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

Traceback (most recent call last):
File "D:\Dan\Python\Xarphus\xarphus\subclass_master_data_load_data_item.py", line 140, in populate_item
self.populate_item_signal.emit(next(self._element))
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 205, in select_all
for record in dict_store_session_query[category]():
File "D:\Dan\Python\Xarphus\xarphus\core\manage_data_manipulation_master_data.py", line 194, in <lambda>
'person_title': lambda: self._session.query(PERSON_TITLE),
File "C:\Python27\lib\site-packages\sqlalchemy\orm\session.py", line 1362, in query
return self._query_cls(entities, self, **kwargs)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 139, in __init__
self._set_entities(entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 150, in _set_entities
self._set_entity_selectables(self._entities)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 180, in _set_entity_selectables
ent.setup_entity(*d[entity])
File "C:\Python27\lib\site-packages\sqlalchemy\orm\query.py", line 3585, in setup_entity
self._with_polymorphic = ext_info.with_polymorphic_mappers
File "C:\Python27\lib\site-packages\sqlalchemy\util\langhelpers.py", line 764, in __get__
obj.__dict__[self.__name__] = result = self.fget(obj)
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1948, in _with_polymorphic_mappers
configure_mappers()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 2872, in configure_mappers
mapper._post_configure_properties()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\mapper.py", line 1765, in _post_configure_properties
prop.init()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\interfaces.py", line 184, in init
self.do_init()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1654, in do_init
self._setup_join_conditions()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1729, in _setup_join_conditions
can_be_synced_fn=self._columns_are_mapped
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 1987, in __init__
self._determine_joins()
File "C:\Python27\lib\site-packages\sqlalchemy\orm\relationships.py", line 2114, in _determine_joins
% self.prop)
AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship FAMILY.person - there are multiple foreign key paths linking the tables. Specify the 'foreign_keys' argument, providing a list of those columns which should be counted as containing a foreign key reference to the parent table.

我们会在那里。 SQLALchey 显然对来自同一个表的两个外键有问题?给你的问题:如何建模才能最好地展示人与人之间的相互关系?因为经过我的推理,我至少需要 person 表中的两个外键,才能建立人员之间的关系。

【问题讨论】:

  • 当遇到异常时,试着用异常文本搜索一下。 SQLA 对指向同一个键的 2 个外键没有问题,但它不是通灵的,因此您必须定义在关系中使用哪个外键。
  • 副本有助于解决这个问题,但我必须承认我根本不理解这个模型:你的家人真的有两个人:“一个人和一个家庭人”?或者这是什么意思?

标签: python python-2.7 sqlalchemy


【解决方案1】:

您对映射器类FAMILY 的定义存在两个主要问题。

(1) 您已经两次将PERSON 引用为外键,因此您必须明确告诉SQLAlchemy 如何加入PERSON,请为每个关系设置foreign_keys 参数。

(2) 您使用了与backref 相同的值。 backref (FAMILY) 的值将成为 PERSON 类的属性名称。查看您的FAMILY,有两个属性分别名为person 和family_person,那么PERSON 类应该有两个不同的属性。

另外,在您的代码中,FAMILY 和 PERSON 之间的关系是多对一的,因此 dynamic 值对于参数 lazy 无效,您应该使用默认值。下面是示例代码:

class FAMILY(Base):

    __tablename__ = "family"

    id = Column(Integer, primary_key=True, unique=True, autoincrement=True)
    status = Column(String(255), nullable=False)

    person_id = Column(Integer, ForeignKey('person.id'))
    person = relationship("PERSON", backref='family_to',
                          foreign_keys=[person_id],
                          )

    family_person_id = Column(Integer, ForeignKey('person.id'))
    family_person = relationship("PERSON",
                                 foreign_keys=[family_person_id],
                                 backref='family_from')

这里有一些与您的问题相关的有用链接:Refer a table twice、Relationship configration

谢谢!

【讨论】:

  • 助教。你的解决方案就像一个魅力。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-02-13
  • 1970-01-01
  • 2022-01-08
相关资源
最近更新 更多