2014-10-02 80 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值將被正確處理。