<p>与“boolean flag”方法相比,您最初想到的group_id方法有几个优点。在</p>
<p>首先,它很自然地受到限制,因此每个用户只有一个主组。另一方面,装载user.primary_组意味着ORM可以通过它的主键来标识这个相关的行,并且可以在标识映射中本地查找它,或者发出一个简单的按主键选择,而不是发出一个查询,其中包含一个很难索引的WHERE子句,其中包含一个布尔值。另一个问题是,不需要进入association对象模式,它简化了关联表的使用,并允许SQLAlchemy更有效地处理来自/到该表的加载和更新。在</p>
<p>下面我们使用事件,包括捕获“remove”事件的@validates的新版本(从0.7.7开始),以确保对用户组以及User.primary_组保持同步。(如果在旧版本的0.7上,可以使用属性“remove”事件或AttributeExtension.remove“如果您仍然使用0.6或更早版本,则使用扩展方法)。如果您希望在数据库级别强制执行此操作,则可以使用触发器来验证所需的完整性:</p>
<pre><code>from sqlalchemy import *
from sqlalchemy.orm import *
from sqlalchemy.ext.declarative import declarative_base
Base= declarative_base()
_usergroup_table = Table('usergroup_table', Base.metadata,
Column('user_id', Integer, ForeignKey('user.id')),
Column('group_id', Integer, ForeignKey('group.id')))
class User(Base):
__tablename__ = 'user'
id = Column(Integer, primary_key=True)
name = Column(String(60), nullable=False, unique=True)
group_id = Column(Integer, ForeignKey('group.id'), nullable=False)
primary_group = relationship("Group")
@validates('primary_group')
def _add_pg(self, key, target):
self.groups.add(target)
return target
@validates('groups', include_removes=True)
def _modify_groups(self, key, target, is_remove):
if is_remove and target is self.primary_group:
del self.primary_group
return target
class Group(Base):
__tablename__ = 'group'
id = Column(Integer, primary_key=True)
name = Column(String(60), nullable=False)
users = relationship('User', secondary=_usergroup_table,
backref=backref('groups', collection_class=set))
e = create_engine("sqlite://", echo=True)
Base.metadata.create_all(e)
s = Session(e)
g1, g2, g3 = Group(name='g1'), Group(name='g2'), Group(name='g3')
u1 = User(name='u1', primary_group=g1)
u1.groups.update([g2, g3])
s.add_all([
g1, g2, g3, u1
])
s.commit()
u1.groups.remove(g1)
assert u1.primary_group is None
u1.primary_group = g2
s.commit()
</code></pre>