即使指定了foreign_keys,AmbiguousForeignKeysError

时间:2019-05-22 20:37:38

标签: python sqlalchemy

我正在为SQLAlchemy设置一些表对象。 我有一个用户和结帐表。我想将一个用户对象与签入和签出相关联,它们都记录在同一个签出对象中,因此我有一个与每个签出对象相关联的in_user和out_user。

我遇到了sqlalchemy.exc.AmbiguousForeignKeysError

引用确切的错误消息:

sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Checkout.out_auth_user - 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.

我已经完成了错误消息的请求(请参见下文),但是错误仍然发生。

我最初仅指定用户电子邮件,因为我希望将来能够删除用户而不会破坏历史数据。但是,我尝试添加用户ID,但仍然遇到相同的错误。

在StackOverflow上有很多类似的问题,但是我找不到一个能解决我的问题的问题,并且大多数问题都与不支持foreign_keys关系参数的sqlalchemy的较旧版本一起使用。似乎这种情况经常发生在反向引用中,但是据我所知,我没有使用它们。这是从签出对象到两个用户对象的简单单向链接。

Flask foreign_keys still shows AmbiguousForeignKeysError

sqlalchemy , AmbiguousForeignKeysError

完整代码位于github上的https://github.com/ACMWM/hwcheckout

以下是MRE

from sqlalchemy import create_engine
from sqlalchemy.orm import scoped_session, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

from sqlalchemy import Column, Boolean, Integer, String, ForeignKey, DateTime
from sqlalchemy.orm import relationship

db = "sqlite:///mre.db"
engine = create_engine(db, convert_unicode=True)
db_session = scoped_session(sessionmaker(autocommit=False,
                                         autoflush=False,
                                         bind=engine))

Base = declarative_base()
Base.query = db_session.query_property()

class User(Base):
    __tablename__ = "users"
    id = Column(Integer, primary_key=True)
    email = Column(String)

class HW(Base):
    __tablename__ = "HW"
    id = Column(Integer, primary_key=True)

class Checkout(Base):
    __tablename__ = "Checkouts"

    what = Column(Integer, ForeignKey(HW.id))
    hardware = relationship(HW, foreign_keys=[what])

    id = Column(Integer, primary_key=True)
    out_auth_id = Column(Integer, ForeignKey(User.id))
    out_auth_email = Column(String, ForeignKey(User.email))
    out_auth_user = relationship(User, foreign_keys=[out_auth_id, out_auth_email])

    in_auth_id = Column(Integer, ForeignKey(User.id))
    in_auth_email = Column(String, ForeignKey(User.email))
    in_auth_user = relationship(User, foreign_keys=[in_auth_id, in_auth_email])

Base.metadata.create_all(bind=engine, checkfirst=True)

u = User(email="test@example.com")
chk = Checkout(out_auth_user_id=u.id,out_auth_user_email=u.email)

我正在使用SQLAlchemy 1.3.3

编辑:删除模型的双重导入。仍然出现相同的错误

再次编辑:获得MRE重现错误

Postgres编辑:不知道这是否有帮助,但是当我尝试将代码移至真实数据库时,出现此错误:

sqlalchemy.exc.ProgrammingError: (psycopg2.errors.InvalidForeignKey) there is no unique constraint matching given keys for referenced table "users"
[SQL:
 CREATE TABLE "Checkouts" (
         id SERIAL NOT NULL,
         outdate TIMESTAMP WITHOUT TIME ZONE,
         returndate TIMESTAMP WITHOUT TIME ZONE,
         who VARCHAR,
         reason VARCHAR,
         quantity INTEGER,
         what INTEGER,
         out_auth_id INTEGER,
         out_auth_email VARCHAR,
         in_auth_id INTEGER,
         in_auth_email VARCHAR,
         PRIMARY KEY (id),
         UNIQUE (id),
         FOREIGN KEY(what) REFERENCES "HW" (id),
         FOREIGN KEY(out_auth_id) REFERENCES users (id),
         FOREIGN KEY(out_auth_email) REFERENCES users (email),
         FOREIGN KEY(in_auth_id) REFERENCES users (id),
         FOREIGN KEY(in_auth_email) REFERENCES users (email)
 )
]

1 个答案:

答案 0 :(得分:0)

尝试更改您的Checkout模型定义:

class Checkout(Base):
    __tablename__ = "Checkouts"

    what = Column(Integer, ForeignKey(HW.id))
    hardware = relationship(HW, foreign_keys=[what])

    id = Column(Integer, primary_key=True)
    out_auth_id = Column(Integer, ForeignKey(User.id))
    out_auth_email = Column(String, ForeignKey(User.email)) 

    in_auth_id = Column(Integer, ForeignKey(User.id))
    in_auth_email = Column(String, ForeignKey(User.email))

    out_auth_user = relationship('User', foreign_keys=[out_auth_id])
    in_auth_user = relationship('User', foreign_keys=[in_auth_id])

    out_auth_user_by_email = relationship('User', foreign_keys=[out_auth_email])
    in_auth_user_by_email = relationship('User', foreign_keys=[in_auth_email])

文档:Okhttp documentation