【问题标题】:Using multiple foreignkeys returns sqlalchemy.exc.AmbiguousForeignKeysError使用多个外键返回 sqlalchemy.exc.AmbiguousForeignKeysError
【发布时间】:2021-02-15 05:02:05
【问题描述】:

可能是重复的,但没有任何效果。 如有重复,请链接

我正在尝试建立一对多的关系(Route 可以被许多 index_GridCell 使用),但我发现的每个解决方案仍然会引发异常: sqlalchemy.exc.AmbiguousForeignKeysError: Could not determine join condition between parent/child tables on relationship Route.igc - 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.

我尝试了所有我能找到的东西,但还是回到了零。我只知道问题出在使用多个外键。

我有当前的models.py:

import pickle
from app import db

class Route(db.Model):

    id = db.Column(db.Integer, primary_key=True)
    url = db.Column(db.String(128))

    total_accesses = db.Column(db.Integer)
    last_access = db.Column(db.DateTime)

    igc = db.relationship('index_GridCell', backref = 'route')

    def query_by_id(id) -> list:
        return Route.query.filter_by(id = id).all()


class index_GridCell(db.Model):
    id = db.Column(db.Integer, primary_key=True)

    route_id = db.Column(db.Integer, db.ForeignKey('route.id')) #just for management
    route_url = db.Column(db.String, db.ForeignKey('route.url'))

    title = db.Column(db.String(128))
    description = db.Column(db.String(128))
    tags = db.Column(db.PickleType)

我用它来创建它们:

rt = Route(url = '/', total_accesses = 0, last_access = 0)
i_gc = index_GridCell(title = 'test_title', description = 'test_desc', tags = ['test', 'tags'], route = rt)
        
db.session.add(rt)
db.session.add(i_gc)
db.session.commit()

版本:
Python 3.7.2
SQLAlchemy 1.3.23
Flask-SQLAlchemy 2.4.4
烧瓶 1.1.2

【问题讨论】:

  • 外键是对另一个表的主键的引用,它定义了唯一性。可以使用此外键加载引用的数据记录或对象。您应该删除在“index_GridCell”中引用“route.url”的外键。为了使您的示例正常工作,它只需要主键“index.id”上的外键。查看these 示例。
  • 那么要获取 url,而不是使用外键,是使用 route_id 并在数据库中通过相应的 Route 进行搜索?由于优化,我试图避免这种情况,但我不确定
  • 我不太明白你的意思。一个路由有多个 IndexGridCell,一个 IndexGridCell 只属于一个路由。更容易想象这些表格。关系的产生取决于保存外键的表。你想得到一个url的所有路由吗?是否要查询 IndexGridCell 的引用路由的关联 url?你想达到什么目标?
  • 一个Route可以有多个indexGridCell,但是一个indexGridCell必须属于一个Route。是的,当我查询 indexGridCell 时,我想要来自关联路由的 url,而不使用 route_id 进行另一个查询。你说的基本上都是我需要的......
  • 当然可以将url定义为外键。但是,这意味着它被定义为路由表中的主键,因此是唯一的。因此,您可以不使用列 ID。这有点古怪,增加了数据库的存储需求。作为替代方案,如果您使用 SQL JOIN 语句,则可以一次性加载关系。您可以通过在关系中设置lazy='joined' 来做到这一点。但是,也可以使用 join 制定自己的查询。

标签: python-3.x flask flask-sqlalchemy


【解决方案1】:

我放弃并解决了问题:

Models.py:

class Route(db.Model):
    __tablename__ = 'route'

    id = db.Column(db.Integer, primary_key = True)
    url = db.Column(db.String(64), primary_key = True)

    total_accesses = db.Column(db.Integer, nullable = False)
    last_access = db.Column(db.DateTime, nullable = False)

    def query_by_id(id) -> list:
        return Route.query.filter_by(id = id).all()
    
    def get_last_id() -> int:
        qr = Route.query.order_by(Route.id.desc()).first()
        return qr.id if qr else 0


class index_GridCell(db.Model):
    __tablename__ = 'i_gc'

    id = db.Column(db.Integer, primary_key=True, nullable = False)

    route_id = db.Column(db.Integer, db.ForeignKey('route.id'), nullable = False)
    route_url = db.Column(db.String, db.ForeignKey('route.url'), nullable = False)

    route = db.relationship('Route', foreign_keys = [route_id])
    route1 = db.relationship('Route', foreign_keys = [route_url])

    title = db.Column(db.String(128), nullable = False)
    description = db.Column(db.String(128), nullable = False)
    tags = db.Column(db.PickleType, nullable = False)

app.py: 创建数据库条目

form_url = request.form['url']
form_title = request.form['title']
form_description = request.form['description']
form_tags = ''.join(request.form['tags'].split()).split(',')

rt = Route(id = Route.get_last_id() + 1, url = form_url, total_accesses = 0, last_access = dt.datetime.now())
i_gc = index_GridCell(title = form_title, description = form_description, tags = form_tags,
            route = rt,
            route1 = rt)
        
db.session.add(rt)
db.session.add(i_gc)
db.session.commit()

我从Route 端删除了关系,并为我需要的每个外键做了一个,然后在创建新的index_GridCell 时,我指定route=rt, route1=rt
如果我需要另一个外键,我会指定route2=rt,创建一个新的关系route2 = db.relationship('Route', foreign_keys = [<my_foreign_key>])
由于自动增量不适用于 SQLite 和复合主键,这是什么意思,我需要自己自动增加 Route.id,如果不这样做,他将为 null 并引发异常。

这可能是解决这个问题的最糟糕的方法之一,但我找不到任何解决方案,而且是一个个人项目,我真的不需要花哨的东西。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-05-29
    • 1970-01-01
    • 2015-08-16
    • 1970-01-01
    • 2017-08-21
    • 1970-01-01
    • 1970-01-01
    • 2018-10-10
    相关资源
    最近更新 更多