2014-10-02 82 views
0

我已经做了一些阅读和Google搜索,但我仍然不确定是否有一种本地/内置的方式在SQLAlchemy对象中创建映射属性,创建一个集合样属性为类似的方案:在SQLAlchemy中创建一个类似映射的属性

User        UserTag 
+----+-----------------+   +---------+-----------+ 
| id | email   |   | user_id | tag  | 
+----+-----------------+   +---------+-----------+ 
| 1 | [email protected] |   | 1  | footag | 
| 2 | [email protected] |   | 1  | something |  
+----+-----------------+   | 1  | tagbar | 
           | 2  | something | 
           | 2  | 3rdtag | 
           +---------+-----------+ 

使每个用户对象具有User.tags映射属性,它是(或行为像)一组字符串 - 例如以下将工作:

>>> user = session.query(User).filter(User.id == 1).one() 
>>> print user.tags 
set(['tagbar', 'something', 'footag']) 
+0

你需要什么具体的一套?唯一性? O(1)查找? – 2014-10-02 17:39:43

+0

好吧,虽然老实说,查找时间并不重要,因为我不认为映射值的数量很大;每个用户最多可以有10个左右的标签,而且大部分我都想知道user.tags中的'tagbar'。 映射表具有在(user_id,tag)上定义的唯一键,因此在数据库级别保证了唯一性。对我来说,为它设置一套或类似的数据结构是很有意义的。 – shevron 2014-10-02 19:34:26

回答

0

使用Association Proxy来实现这一目标:

# create sample data 
foo = User(
    email='[email protected]', 
    tagset={'footag', 'something', 'tagbar'} 
) 
bar = User(
    email='[email protected]', 
    tagset={'something', '3rdtag'} 
) 
session.add(foo) 
session.add(bar) 
session.commit() 

bar = session.query(User).get(2) 
assert 'something' in bar.tagset 
bar.tagset.remove('something') 
assert 'something' not in bar.tagset 

还加入了UserTag用相同的:

class User(Base): 
    __tablename__ = 'users' 

    id = Column(Integer, primary_key=True) 
    email = Column(String, nullable=False) 
    tags = relationship('UserTag', collection_class=set, 
         cascade="all, delete, delete-orphan") 
    tagset = association_proxy(
     'tags', 'tag_name', 
     creator=lambda tag_name: UserTag(tag_name=tag_name), 
    ) 

class UserTag(Base): 
    __tablename__ = 'user_tags' 
    user_id = Column(Integer, ForeignKey('users.id'), primary_key=True) 
    tag_name = Column(String, primary_key=True) 

然后你就可以用的方式模型工作tag_name值将被正确处理。