Sure, here’s the translation: “SQLAlchemy模型类是否可以互相指向具有ForeignKey列?”

huangapple go评论64阅读模式
英文:

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

huangapple
  • 本文由 发表于 2023年6月8日 05:12:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/76427138.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定