sqlalchemy.exc.AmbiguousForeignKeysError:如何在Flask SQLAlchemy中定义两个引用同一主键的外键?

时间:2020-02-13 17:55:03

标签: flask sqlalchemy flask-sqlalchemy

我正在用Flask创建一个记分API。尽管经过数小时的谷歌搜索,但我仍无法使数据库正常工作。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///test.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)


class Person (db.Model):
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), nullable=False)
    first_name = db.Column(db.String(64), nullable=False)
    last_name = db.Column(db.String(64), nullable=False)
    birthdate = db.Column(db.String(64), nullable=True)
    description = db.Column(db.String(256), nullable=True)

    match1 = db.relationship("Match", back_populates="person")
    match2 = db.relationship("Match", back_populates="person2")



class Match (db.Model):
    id = db.Column(db.Integer, primary_key=True)
    game = db.Column(db.String(64), db.ForeignKey("game.id"))
    place = db.Column(db.String(64), nullable=True)
    time = db.Column(db.String(32), nullable=True)
    player1_id = db.Column(db.Integer, db.ForeignKey("person.id"))
    player2_id = db.Column(db.Integer, db.ForeignKey("person.id"))
    player1_score = db.Column(db.Float, nullable=False)
    player2_score = db.Column(db.Float, nullable=False)
    comment = db.Column(db.String(256), nullable=True)

    games = db.relationship("Game", back_populates="matches")
    person = db.relationship(
        "Person",
        foreign_keys="Match.player1_id",
        back_populates="match1"
    )

    person2 = db.relationship(
        "Person",
        foreign_keys="Match.player2_id",
        back_populates="match2"
    )


class Game (db.Model):
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=True)
    score_type = db.Column(db.Integer, nullable=False)

    matches = db.relationship("Match", back_populates="games")

在Python shell中:

>>> from app import *
>>> db.create_all()
>>> pers1 = Person(username="username",first_name="user",last_name="name")

Traceback (most recent call last):
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 2354, in _determine_joins
    consider_as_foreign_keys=consider_as_foreign_keys,
  File "<string>", line 2, in join_condition
  File "<string>", line 2, in _join_condition
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/util/deprecations.py", line 130, in warned
    return fn(*args, **kwargs)
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/sql/selectable.py", line 923, in _join_condition
    a, b, constraints, consider_as_foreign_keys
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/sql/selectable.py", line 1040, in _joincond_trim_constraints
    "join explicitly." % (a.description, b.description)
sqlalchemy.exc.AmbiguousForeignKeysError: Can't determine join between 
'person' and 'match'; tables have more than one foreign key constraint 
relationship between them. Please specify the 'onclause' of this join 
explicitly.

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "<string>", line 2, in __init__
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/instrumentation.py", line 373, in _new_state_if_none
    state = self._state_constructor(instance, self)
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/util/langhelpers.py", line 855, in __get__
    obj.__dict__[self.__name__] = result = self.fget(obj)
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/instrumentation.py", line 199, in _state_constructor
    self.dispatch.first_init(self, self.class_)
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/event/attr.py", line 297, in __call__
    fn(*args, **kw)
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 3341, in _event_on_first_init
    configure_mappers()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 3229, in configure_mappers
    mapper._post_configure_properties()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/mapper.py", line 1947, in _post_configure_properties
    prop.init()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/interfaces.py", line 196, in init
    self.do_init()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 1854, in do_init
    self._setup_join_conditions()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 1934, in _setup_join_conditions
    can_be_synced_fn=self._columns_are_mapped,
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 2239, in __init__
    self._determine_joins()
  File "/home/USERNAME/pythonvenvs/pwp_3.6/lib/python3.6/site-packages/sqlalchemy/orm/relationships.py", line 2399, in _determine_joins
    "foreign key reference to the parent table." % self.prop
sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Person.match1
- 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.

如何获取Match.player1_id和Match.player2_id来引用Person.id?网络上有很多例子,但我都没有成功。我应该使用backref还是back_populates?

我已经尝试过让Person表中的关系只有一种,其中foreign_keys参数是一个列表。我也无法正常工作。

1 个答案:

答案 0 :(得分:0)

我尝试了您的示例,这是如何使它工作的(但我不确定这是否是您想要实现的目标)。

from flask import Flask
from flask_sqlalchemy import SQLAlchemy

app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///test.db"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)


class Person (db.Model):
    __tablename__ = 'person'
    id = db.Column(db.Integer, primary_key=True)
    username = db.Column(db.String(64), nullable=False)
    first_name = db.Column(db.String(64), nullable=False)
    last_name = db.Column(db.String(64), nullable=False)
    birthdate = db.Column(db.String(64), nullable=True)
    description = db.Column(db.String(256), nullable=True)

    match1 = db.relationship(
        "Match",
        foreign_keys="Match.player1_id",
        backref ="player1"
    )

    match2 = db.relationship(
        "Match",
        foreign_keys="Match.player2_id",
        backref="player2"
    )


class Match (db.Model):
    __tablename__ = 'match'
    id = db.Column(db.Integer, primary_key=True)
    game = db.Column(db.Integer, db.ForeignKey("game.id"))
    place = db.Column(db.String(64), nullable=True)
    time = db.Column(db.String(32), nullable=True)
    player1_id = db.Column(db.Integer, db.ForeignKey("person.id"))
    player2_id = db.Column(db.Integer, db.ForeignKey("person.id"))
    player1_score = db.Column(db.Float, nullable=False)
    player2_score = db.Column(db.Float, nullable=False)
    comment = db.Column(db.String(256), nullable=True)

    games = db.relationship("Game", back_populates="matches")


class Game (db.Model):
    __tablename__ = 'game'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String, nullable=True)
    score_type = db.Column(db.Integer, nullable=False)

    matches = db.relationship("Match", back_populates="games")
相关问题