同一张表的一个对象两个外键

Posted

技术标签:

【中文标题】同一张表的一个对象两个外键【英文标题】:One object two foreign keys to the same table 【发布时间】:2015-12-30 04:07:26 【问题描述】:

我需要有一个与两个用户关联的帖子。作者和版主。我正在尝试这段代码,但没有成功

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    ...
    post = db.relationship('Post', foreign_keys=['posts.id'], backref='post_user', lazy='dynamic')
    post_blame = db.relationship('Post', foreign_keys=['posts.moderated_by'], backref='post_blame', lazy='dynamic')    

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    moderated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)

错误:

ArgumentError: Column-based expression object expected for argument 'foreign_keys'; got: 'posts.id', type <class 'str'>

【问题讨论】:

请发布完整的错误回溯。 已解决基于此线程reddit.com/r/flask/comments/2o4ejl/… 【参考方案1】:

这里的一个问题是您当前正尝试在关系foreign_keys 中使用表列,而不是类属性。

也就是说,您应该使用Post.id,而不是使用posts.id。 (实际上,要引用表格列,您需要使用posts.c.id)。

因此,如果您将原始代码更正为:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    ...
    post = db.relationship('Post', foreign_keys='Post.id', backref='post_user', lazy='dynamic')
    post_blame = db.relationship('Post', foreign_keys='Post.moderated_by', backref='post_blame', lazy='dynamic')    

如果没有,那么还有其他几个选项。首先,您可以在 Post 类中建立这些关系,这样 sqlalchemy 查找外键关系就不会那么模棱两可了。类似的东西

class Post(db.Model):
    __tablename__ = 'posts'
    id = db.Column(db.Integer, primary_key=True)
    ...
    author_id = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    moderated_by = db.Column(db.Integer, db.ForeignKey('users.id'), nullable=False)
    post_user = db.relationship(User, foreign_keys=author_id, backref='post', lazy='dynamic')
    post_blame = db.relationship(User, foreign_keys=moderated_by, backref='post_blame', lazy='dynamic')    

注意在这个版本中,我们不需要将foreign_keys值作为字符串传递,我们可以直接引用范围内的列。

或者,如果您希望在 User 中建立这些关系,您可能需要使用 primaryjoinsqlalchemy 提供更多信息......也许类似于:

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    ...
    post = db.relationship('Post', primaryjoin='User.id == Post.id', backref='post_user', lazy='dynamic')
    post_blame = db.relationship('Post', foreign_keys='User.id == Post.moderated_by', backref='post_blame', lazy='dynamic')    

【讨论】:

第一个示例,我得到的错误类型相同(参数'foreign_keys'需要基于列的表达式对象)。第二个示例 relationship() 得到了一个意外的关键字参数“primary_join” @anvd primary_join 应该是主连接。还刚刚注意到您在foreign_keys 中使用的是表名,而不是类名,我已经相应地修改了我的答案。告诉我进展如何! 我并不真正关心您的赏金,我也不特别关心尝试完全复制您的表和数据库结构以帮助您解决一个相当简单的问题。我只是想提供一些指导……你知道,我怀疑你可能能够做诸如查找文档之类的事情。例如,简单地看一下关系 api 就会告诉你 primary_join 应该是 primaryjoin ... 显然问题没那么简单。四天后有 65 次观看,而我只有“猜测”。顺便说一句谢谢 @donkopotamus,这对我有帮助,非常感谢!附带说明一下,sqlalchemy 的文档可以做一些改进。对于这种情况,这就是 it says: a list of columns which are to be used as ...... be passed as a Python-evaluable string when using Declarative. 有时可能会令人困惑。例如,我必须用谷歌搜索到这里!

以上是关于同一张表的一个对象两个外键的主要内容,如果未能解决你的问题,请参考以下文章

子账号表的设计(不用递归实现查询,同一张表做外键)

实体框架,插入了引用最后一个Id的外键,同时也是同一张表上之前的集合

Django过滤同一外键对象的两个字段

在 SQL 中加入来自同一个表的两个外键

实体框架代码优先 - 来自同一个表的两个外键

使用来自同一个表的两个外键进行休眠 - 注释