SQLAlchemy 多对多关联 class
SQLAlchemy many-to-many association class
我有以下两个classes(简体):
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)
我选择了 class 而不是 table 因为 SQLAlchemy 文档建议在我必须存储额外的列时使用 class。
我的问题是我不能 "join" 他们。
我尝试了以下方法:
将引用直接添加到关联table:
task = db.relationship("Task", backref="users")
user = db.relationship("AppUser", backref="tasks")
添加对用户和任务的引用 class:
class User:
[...]
tasks = db.relationship("Solved", backref="users")
class Task:
[...]
users = db.relationship("Solved", backref="tasks")
它们都不起作用。
令我惊讶的是,如果我将 Solved class 更改为 db.Table 对象,它会起作用。
我想尝试关联 class 因为我使用引用已解决但不接受 db.Table 对象的子查询。
我想做的是将 "solved" 个任务添加到列表中:
u = User.query.get([...])
t = Task.query.get([...])
u.tasks.append(t)
db.session.add(u)
db.session.commit()
编辑:
当我检查一个元素是否已经是 "Solved":
# 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 关联,但不适用于 class.
关联
我也试过像here (SQLAlchemy docs)这样的关联代理,但我得到了和上面一样的错误。
我能够解决问题。
我主要复制了 association proxy tutorial from the official doc
以下是给其他挣扎的人的一些陷阱和提示:
- 在您想加入的 class 之后写下您的协会 class。
(对我们大多数人来说很明显,但检查一下也无妨)
- 向您的关联添加
__init__
功能 class!
- 仔细检查您的反向引用、class 和 table 名称。
我自己没有仔细研究过什么时候使用哪个关键字,但大多数时候都是你的错误。
我有以下两个classes(简体):
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)
我选择了 class 而不是 table 因为 SQLAlchemy 文档建议在我必须存储额外的列时使用 class。
我的问题是我不能 "join" 他们。 我尝试了以下方法:
将引用直接添加到关联table:
task = db.relationship("Task", backref="users")
user = db.relationship("AppUser", backref="tasks")
添加对用户和任务的引用 class:
class User:
[...]
tasks = db.relationship("Solved", backref="users")
class Task:
[...]
users = db.relationship("Solved", backref="tasks")
它们都不起作用。 令我惊讶的是,如果我将 Solved class 更改为 db.Table 对象,它会起作用。 我想尝试关联 class 因为我使用引用已解决但不接受 db.Table 对象的子查询。
我想做的是将 "solved" 个任务添加到列表中:
u = User.query.get([...])
t = Task.query.get([...])
u.tasks.append(t)
db.session.add(u)
db.session.commit()
编辑:
当我检查一个元素是否已经是 "Solved":
# 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 关联,但不适用于 class.
关联我也试过像here (SQLAlchemy docs)这样的关联代理,但我得到了和上面一样的错误。
我能够解决问题。 我主要复制了 association proxy tutorial from the official doc 以下是给其他挣扎的人的一些陷阱和提示:
- 在您想加入的 class 之后写下您的协会 class。 (对我们大多数人来说很明显,但检查一下也无妨)
- 向您的关联添加
__init__
功能 class! - 仔细检查您的反向引用、class 和 table 名称。 我自己没有仔细研究过什么时候使用哪个关键字,但大多数时候都是你的错误。