自我参考很多很多烧瓶 - sqlalchemy

时间:2015-06-02 22:25:53

标签: python postgresql flask sqlalchemy flask-sqlalchemy

我为我的生活无法弄清楚为什么这种自我引用的多对多不会幸福:

minor_contains = db.Table(
    'minor_contains',
    db.Column('parent_id', db.Integer, db.ForeignKey('minors.id'),
            primary_key=True),
    db.Column('contains_id', db.Integer, db.ForeignKey('minors.id'),
            primary_key=True))

class Minor(db.Model):
    __tablename__ = 'minors'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String())
    ...
    contains = db.relationship(
        "Minor",
        secondary=minor_contains,
        primaryjoin="id == minor_contains.c.parent_id",
        secondaryjoin="id == minor_contains.c.contains_id",
        backref="contained_by",
        lazy='dynamic')

我已经尝试基于我在SQLAlchemy和Flask-SQLAlchemy上看到的示例以几种不同的方式重新编写它,但是我总是最终得到以下错误消息,或者我最终在某个地方无限循环

E ArgumentError:找不到涉及Minor.contains关系的主要连接条件“minor_contains.parent_id =:parent_id_1”的本地映射外键列的任何简单相等表达式。确保引用列与ForeignKey或ForeignKeyConstraint相关联,或者在带有foreign()注释的连接条件中进行注释。为了允许“==”以外的比较运算符,可以将关系标记为viewonly = True。

更新

我真的无法理解错误消息,因为它显示了连接表中的列与自身进行比较,其中连接上的条件应该是minors表的PK与连接表中的FK相比。

我还会添加一个永远挂起的版本。你会看到我一直在改变变量名称,只是一遍又一遍地重写它,希望如果我重新尝试它,我会在第二次或第五次变得更聪明。

minor_contains = db.Table(
    'minor_contains',
    db.Column('parent_minor_id', db.Integer, db.ForeignKey('minors.id'),
            primary_key=True),
    db.Column('contains_minor_id', db.Integer, db.ForeignKey('minors.id'),
            primary_key=True))

class Minor(db.Model):
    __tablename__ = 'minors'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String())
    ...
    contains = db.relationship(
        "Minor",
        secondary=minor_contains,
        primaryjoin=id==minor_contains.c.parent_minor_id,
        secondaryjoin=id==minor_contains.c.contains_minor_id,
        backref=db.backref("minor_contains", lazy='dynamic'))

2 个答案:

答案 0 :(得分:3)

我认为有必要在连接条件中指定模型名称。

contains = db.relationship(
    "Minor",
    secondary=minor_contains,
    primaryjoin="Minor.id == minor_contains.c.parent_id",
    secondaryjoin="Minor.id == minor_contains.c.contains_id",
    backref=db.backref('minor_contains', lazy='dynamic'),
    lazy='dynamic')

我有同样的问题,它解决了问题。我在这里找到了一个有用的答案 link

答案 1 :(得分:0)

你试过这个吗?

minor_contains = db.Table(
    'minor_contains',
    db.Column('parent_id', db.Integer, db.ForeignKey('minors.id'),
        primary_key=True),
    db.Column('contains_id', db.Integer, db.ForeignKey('minors.id'),
        primary_key=True))

class Minor(db.Model):
    __tablename__ = 'minors'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String())
    ...
    contains = db.relationship(
        "Minor",
        secondary=minor_contains,
        primaryjoin="id == minor_contains.c.parent_id",
        secondaryjoin="id == minor_contains.c.contains_id",
        backref=db.backref('minor_contains', lazy='dynamic'),
        lazy='dynamic')