多个外键引用 SQLAlchemy 中的同一表列

问题描述

我正在创建一个评级系统。评分是一个表,其中包含单个评分作为行。每个评级都有一个“评级者”和一个“评级者”。这两列通过外键引用不同的表“User”。但是,它们都引用了相同的 user.id 列。代码

class rating(db.Model):
  id = db.Column(db.Integer,primary_key=True)
  rater_id = db.Column(db.Integer,db.ForeignKey('user.id'),nullable=False)
  ratee_id = db.Column(db.Integer,nullable=False)

以下是它们在 User 类(表)中的表示方式:

class User(db.Model,UserMixin):
  id = db.Column(db.Integer,primary_key=True)
  username = db.Column(db.String(32),unique=True,nullable=False)
  ratesOfOthers = db.relationship('rating',backref='rater',lazy=True)
  ratingsByOthers = db.relationship('rating',backref='ratee',lazy=True)

现在,当我尝试使用此关系时,出现以下错误

sqlalchemy.exc.AmbiguousForeignKeysError:无法确定关系 User.ratesOfOthers 上的父/子表之间的连接条件 - 有多个外键路径链接表。指定“foreign_keys”参数,提供应被视为包含对父表的外键引用的列的列表。

我曾尝试在 User 类中使用 foreign_keys 参数,但没有任何作用。任何帮助将不胜感激。

解决方法

假设在您的场景中,一个用户可以评价其他用户,他们(他们自己)也可以被评价。基本上,有一个名为 User 的表引用应用程序中的其他用户。

将类的实例链接到同一类的其他实例的关系称为自引用关系,这正是您在这里所拥有的。

下图展示了这种跟踪评分的自我参照多对多关系:

enter image description here

Ratings 表是关系的关联表。此表中的外键指向 User 表中的条目,因为它将用户链接到用户。

要将此表添加到您的数据库中,您可以这样做:

ratings = db.Table('ratings'
                   db.Column('my_ratings_id',db.Integer,db.ForeignKey('user.id'))
                   db.Column('other_people_rating_id',db.Integet,db.ForeignKey('user.id'))
                   )

这是一个辅助表(如上所示直接翻译),除了外键外没有其他数据。因此,它是在没有关联模型类的情况下创建的。

要在 User 表中声明多对多关系,请添加:

class User(UserMixin,db.Model):
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(32),unique=True,nullable=False)
    
    
    def __repr__(self):
        return f'{self.username}'
        
    my_ratings = db.relationship(
                                 'User',secondary=ratings,primaryjoin=(ratings.c.my_ratings_id == id),secondaryjoin=(ratings.c.other_people_rating_id == id),backref = db.backref('other_people_rating',lazy='dynamic'),lazy='dynamic'
                                 )

我定义的关系是从左侧用户看到的名称为 my_ratings 的关系,因为当您从左侧查询此关系时,您将获得右侧所有用户的列表。在视觉上,这就是我的意思:

enter image description here

检查 db.relationship() 调用的所有参数,您将看到:

  • User 是关系的右侧实体。
  • secondary 配置 ratings 关联表
  • primaryjoin 表示链接左侧实体与关联表的条件。 user id 应该匹配 my_ratings_id
  • secondaryjoin 表示将右侧实体与关联表链接的条件。同样,other_people_rating_id 应该匹配 user id
  • backref 定义了如何从右侧实体访问此关系。从左边看,关系被命名为 my_ratings,所以从右边看,我决定将它命名为 other_people_rating 来代表链接到右边目标用户的所有左边用户。
  • dynamic 模式用于将查询设置为在特别请求之前不运行。
  • 第二个 lazy 参数适用于左侧查询而不是右侧查询。