英文:
Can SQLAlchemy model classes each have a ForeignKey column pointing to each other?
问题
我有两个SQLAlchemy类,每个类都有一个指向另一个类的外键。
我得到了这个错误:
sqlalchemy.exc.AmbiguousForeignKeysError:无法确定父/子表之间的关系User.company的连接条件 - 有多个外键路径链接这些表。请指定“foreign_keys”参数,提供应视为包含对父表的外键引用的列列表。
根据在线搜索,我知道SQLAlchemy无法确定父表和子表之间的连接条件,因为存在多个外键路径链接这些表。
这是否被视为不良实践,我应该删除其中一个外键?
我尝试在relationship函数中添加了foreign_keys参数,但没有帮助。
请详细说明应如何处理这种情况。
谢谢
英文:
I have two SQLAlchemy classes, each having a foreign key pointing to the other class.
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
user_name = Column(String, nullable=false)
company_id = Column(Integer, ForeignKey("companies.id")
company = relationship("Item", back_populates="users")
class Company(Base):
__tablename__ = "companies"
id = Column(Integer, primary_key=True)
name = Column(String)
modified_by = Column(Integer, ForeignKey("users.id")
users = relationship("User", back_populates="company")
I get this error
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship User.company - 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.
I know from searching online that SQLAlchemy cannot determine the join condition between parent and child tables due to multiple foreign key paths linking the tables.
Is this considered bad practice and should I remove one of the foreign keys?
I tried adding the foreign_keys argument in the relationship function, but it didn't help.
Please give a good explanation of how this should be handled.
Thanks
答案1
得分: 0
这是一个关于SQLAlchemy的代码示例,其中包含一些关于用户和公司的模型定义以及数据库操作。你可以在以下链接中找到更多关于这个主题的信息:rows-that-point-to-themselves-mutually-dependent-rows。另外,下面是一些重要的日志信息,特别是在"post update"时进行了一些数据库操作。
英文:
This is a "thing". The docs talk about it here (second case): rows-that-point-to-themselves-mutually-dependent-rows
import sys
from sqlalchemy import (
create_engine,
Integer,
String,
)
from sqlalchemy.schema import (
Column,
ForeignKey,
)
from sqlalchemy.sql import select
from sqlalchemy.orm import declarative_base, Session, aliased, relationship, joinedload
Base = declarative_base()
username, password, db = sys.argv[1:4]
engine = create_engine(f"postgresql+psycopg2://{username}:{password}@/{db}", echo=True)
class User(Base):
__tablename__ = "users"
id = Column(Integer, primary_key=True)
user_name = Column(String, nullable=False)
company_id = Column(Integer, ForeignKey("companies.id"))
company = relationship("Company", back_populates="users", primaryjoin="User.company_id == Company.id")
modified_companies = relationship("Company", back_populates="modified_by", primaryjoin="User.id == Company.modified_by_id", post_update=True)
class Company(Base):
__tablename__ = "companies"
id = Column(Integer, primary_key=True)
name = Column(String)
# added _id suffix to prevent clash with relationship
modified_by_id = Column(Integer, ForeignKey("users.id"), nullable=True)
modified_by = relationship("User", primaryjoin=modified_by_id == User.id, post_update=True)
users = relationship("User", primaryjoin=id == User.company_id, back_populates="company")
Base.metadata.create_all(engine)
with Session(engine) as session:
u1 = User(user_name="user1")
c1 = Company(name="company1", users=[u1], modified_by=u1)
session.add(c1)
session.commit()
with Session(engine) as session:
company = session.execute(select(Company)).scalar()
assert len(company.users) == 1
assert company.users[0] == company.modified_by
here are the important logs, you can see post update:
2023-06-07 16:43:55,569 INFO sqlalchemy.engine.Engine BEGIN (implicit)
2023-06-07 16:43:55,571 INFO sqlalchemy.engine.Engine INSERT INTO companies (name, modified_by_id) VALUES (%(name)s, %(modified_by_id)s) RETURNING companies.id
2023-06-07 16:43:55,571 INFO sqlalchemy.engine.Engine [generated in 0.00019s] {'name': 'company1', 'modified_by_id': None}
2023-06-07 16:43:55,574 INFO sqlalchemy.engine.Engine INSERT INTO users (user_name, company_id) VALUES (%(user_name)s, %(company_id)s) RETURNING users.id
2023-06-07 16:43:55,574 INFO sqlalchemy.engine.Engine [generated in 0.00017s] {'user_name': 'user1', 'company_id': 1}
2023-06-07 16:43:55,577 INFO sqlalchemy.engine.Engine UPDATE companies SET modified_by_id=%(modified_by_id)s WHERE companies.id = %(companies_id)s
2023-06-07 16:43:55,577 INFO sqlalchemy.engine.Engine [generated in 0.00018s] {'modified_by_id': 1, 'companies_id': 1}
2023-06-07 16:43:55,579 INFO sqlalchemy.engine.Engine COMMIT
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论