SQLAlchemy多对多关联类

时间:2015-07-19 00:22:30

标签: python sqlalchemy flask-sqlalchemy

我有以下两个类(简化):

class User(db.Model):
    __tablename__ = "AppUser"
    user_id = db.Column(db.Integer, primary_key=True)

class Task(db.Model):
    __tablename__ = "Task"
    task_id = db.Column(db.Integer, primary_key=True)

我想加入多对多关联,但是除了主键之外还要存储一个额外的列:

class Solved(db.Model):
    __tablename__ = "Solved"
    user_id = db.Column(db.Integer, db.ForeignKey("AppUser.user_id"), primary_key=True)
    task_id = db.Column(db.Integer, db.ForeignKey("Task.task_id"), primary_key=True)
    solved_at = db.Column(db.DateTime, default=datetime.utcnow)

我已经选择了该类,因为SQLAlchemy文档建议在必须存储其他列时使用类。

我的问题是我无法加入"他们。 我尝试了以下方法:

直接将引用添加到关联表:

task = db.relationship("Task", backref="users")
user = db.relationship("AppUser", backref="tasks")

添加对用户和任务类的引用:

class User:
    [...]
    tasks = db.relationship("Solved", backref="users")

class Task:
    [...]
    users = db.relationship("Solved", backref="tasks")

它们都不起作用。 令我惊讶的是,如果我将Solved类更改为db.Table对象,它会起作用。 我想尝试关联类,因为我使用引用Solved但不接受db.Table对象的子查询。

我想要做的是添加"已解决"任务到列表:

u = User.query.get([...])
t = Task.query.get([...])
u.tasks.append(t)
db.session.add(u)
db.session.commit()

编辑:

当我检查某个元素是否已经过了"已解决":

# My models have name fields
u.tasks.filter_by(name="abc")

我收到以下错误:

AttributeError: '_AssociationList' object has no attribute 'filter_by'

当我将新元素追加到列表中时:

u.tasks.append(t)
db.session.add(u) # These two steps work
db.session.commit() # Error

sqlalchemy.exc.InvalidRequestError: One or more mappers failed to initialize - can't proceed with initialization of other mappers.  Original exception was: relationship 'user' expects a class or a mapper argument (received: <class 'sqlalchemy.sql.schema.Table'>)   

如上所述,它使用简单的db.Table关联,但不使用关联类。

我还尝试了像here (SQLAlchemy docs)这样的关联代理,但我得到了与上面相同的错误。

1 个答案:

答案 0 :(得分:0)

我能够解决问题。 我大部分都复制了association proxy tutorial from the official doc 以下是其他挣扎的人的一些陷阱和提示:

  • 在要加入的课程后编写关联课程。 (对我们大多数人来说很明显,但检查并不痛苦)
  • 在您的关联类中添加__init__函数!
  • 仔细检查您的backrefs,类和表名称。 我自己没有查看何时使用哪个关键字,但大部分时间都是你的错误。