SQLAlchemy lazy=dynamic 与 m2m 关系使用关联对象模式
SQLAlchemy lazy=dynamic with m2m relationship using association object pattern
我在 users
和 roles
之间有一个简单的 m2m 关系 tables:
users_roles = db.Table('users_roles',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('role_id', db.Integer, db.ForeignKey('roles.id')),
db.Column('is_primary', db.Boolean)
)
class User(db.Model):
__tablename__ = 'users'
id = db.Column('id', db.Integer, primary_key=True)
roles = db.relationship('Role', secondary=users_roles, lazy='dynamic', backref=db.backref('users', lazy='dynamic'))
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column('id', db.Integer, primary_key=True)
users = db.relationship('User', secondary=users_roles, lazy='dynamic', backref=db.backref('roles', lazy='dynamic'))
要向 users_roles
table 添加记录,我必须这样做:
role = Role.get(1)
user = User()
user.roles.append(role)
db.session.add(user)
db.session.commit()
没关系,但我在 users_roles
table 中有一个名为 is_primary
的列也应该被填充。
我更改了代码以使用 SQLAlchemy 文档中所述的 Association Object Pattern。
现在我的代码如下所示:
class User(db.Model):
__tablename__ = 'users'
id = db.Column('id', db.Integer, primary_key=True)
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column('id', db.Integer, primary_key=True)
class UserRole(db.Model):
__tablename__ = 'users_roles'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'), primary_key=True)
is_primary = db.Column(db.Boolean)
user = db.relationship(User, backref="users_roles")
role = db.relationship(Role, backref="users_roles")
User.roles = association_proxy("users_roles", "role")
Role.users = association_proxy("users_roles", "user")
效果很好,但我仍然遇到问题。
是否有可能 User.roles(与关联代理一起添加)returns 和 AppenderBaseQuery 我可以添加更多过滤器,例如User.query.get(1).roles.filter_by(...)?
我习惯于在关系声明中使用 lazy=dynamic 来处理普通的多对多关系,但是在将 class 映射到关联 [=43] 之后=] 看来我不能再这样做了。
有办法实现吗?
@IfLoop 我在 post 中遵循了你的建议。非常感谢您的帮助。
好吧,我最终使用以下代码过滤 roles
:
roles = Role.query.filter_by(...).join(UserRole).join(User).filter_by(id=1)
我仍然希望能够做这样的事情:
roles = User.query.get(1).roles.filter_by(...).all()
无论如何,如果几天后我没有得到答案,我会接受这个作为答案。
帮助你太晚了,但我问了自己同样的问题,文档的这一段阐明了代理协会可以做什么:
https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html#querying-with-association-proxies
根据我的理解总结:这不是明确可能的,但对于直接目标是相关对象或集合的关联代理,可以改用面向关系的运算符,例如 .has() 和 .any ()
我不确定这对我有帮助,但如果它能为某人指出他们的解决方案,我会把它放在那里
我在 users
和 roles
之间有一个简单的 m2m 关系 tables:
users_roles = db.Table('users_roles',
db.Column('user_id', db.Integer, db.ForeignKey('users.id')),
db.Column('role_id', db.Integer, db.ForeignKey('roles.id')),
db.Column('is_primary', db.Boolean)
)
class User(db.Model):
__tablename__ = 'users'
id = db.Column('id', db.Integer, primary_key=True)
roles = db.relationship('Role', secondary=users_roles, lazy='dynamic', backref=db.backref('users', lazy='dynamic'))
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column('id', db.Integer, primary_key=True)
users = db.relationship('User', secondary=users_roles, lazy='dynamic', backref=db.backref('roles', lazy='dynamic'))
要向 users_roles
table 添加记录,我必须这样做:
role = Role.get(1)
user = User()
user.roles.append(role)
db.session.add(user)
db.session.commit()
没关系,但我在 users_roles
table 中有一个名为 is_primary
的列也应该被填充。
我更改了代码以使用 SQLAlchemy 文档中所述的 Association Object Pattern。
现在我的代码如下所示:
class User(db.Model):
__tablename__ = 'users'
id = db.Column('id', db.Integer, primary_key=True)
class Role(db.Model):
__tablename__ = 'roles'
id = db.Column('id', db.Integer, primary_key=True)
class UserRole(db.Model):
__tablename__ = 'users_roles'
user_id = db.Column(db.Integer, db.ForeignKey('users.id'), primary_key=True)
role_id = db.Column(db.Integer, db.ForeignKey('roles.id'), primary_key=True)
is_primary = db.Column(db.Boolean)
user = db.relationship(User, backref="users_roles")
role = db.relationship(Role, backref="users_roles")
User.roles = association_proxy("users_roles", "role")
Role.users = association_proxy("users_roles", "user")
效果很好,但我仍然遇到问题。 是否有可能 User.roles(与关联代理一起添加)returns 和 AppenderBaseQuery 我可以添加更多过滤器,例如User.query.get(1).roles.filter_by(...)? 我习惯于在关系声明中使用 lazy=dynamic 来处理普通的多对多关系,但是在将 class 映射到关联 [=43] 之后=] 看来我不能再这样做了。 有办法实现吗?
@IfLoop 我在 post 中遵循了你的建议。非常感谢您的帮助。
好吧,我最终使用以下代码过滤 roles
:
roles = Role.query.filter_by(...).join(UserRole).join(User).filter_by(id=1)
我仍然希望能够做这样的事情:
roles = User.query.get(1).roles.filter_by(...).all()
无论如何,如果几天后我没有得到答案,我会接受这个作为答案。
帮助你太晚了,但我问了自己同样的问题,文档的这一段阐明了代理协会可以做什么: https://docs.sqlalchemy.org/en/14/orm/extensions/associationproxy.html#querying-with-association-proxies
根据我的理解总结:这不是明确可能的,但对于直接目标是相关对象或集合的关联代理,可以改用面向关系的运算符,例如 .has() 和 .any ()
我不确定这对我有帮助,但如果它能为某人指出他们的解决方案,我会把它放在那里