2009-04-23 29 views
15

我有關於SQLAlchemy的問題。我如何在映射類中添加類似字典的屬性,將字符串鍵映射爲字符串值,並將其存儲在數據庫中(與原始映射對象位於同一表或另一個表中)。我想要添加對我的對象的任意標籤的支持。SQLAlchemy - 標記字典

我發現SQLAlchemy的文檔在下面的例子:

from sqlalchemy.orm.collections import column_mapped_collection, attribute_mapped_collection, mapped_collection 

mapper(Item, items_table, properties={ 
# key by column 
'notes': relation(Note, collection_class=column_mapped_collection(notes_table.c.keyword)), 
# or named attribute 
'notes2': relation(Note, collection_class=attribute_mapped_collection('keyword')), 
# or any callable 
'notes3': relation(Note, collection_class=mapped_collection(lambda entity: entity.a + entity.b)) 
}) 

item = Item() 
item.notes['color'] = Note('color', 'blue') 

但我想以下行爲:

mapper(Item, items_table, properties={ 
# key by column 
'notes': relation(...), 
}) 

item = Item() 
item.notes['color'] = 'blue' 

有可能在SQLAlchemy的?

謝謝

回答

21

簡單的答案是

只需使用一個協會代理:

from sqlalchemy import Column, Integer, String, Table, create_engine 
from sqlalchemy import orm, MetaData, Column, ForeignKey 
from sqlalchemy.orm import relation, mapper, sessionmaker 
from sqlalchemy.orm.collections import column_mapped_collection 
from sqlalchemy.ext.associationproxy import association_proxy 

創建測試環境:

engine = create_engine('sqlite:///:memory:', echo=True) 
meta = MetaData(bind=engine) 

定義表:

tb_items = Table('items', meta, 
     Column('id', Integer, primary_key=True), 
     Column('name', String(20)), 
     Column('description', String(100)), 
    ) 
tb_notes = Table('notes', meta, 
     Column('id_item', Integer, ForeignKey('items.id'), primary_key=True), 
     Column('name', String(20), primary_key=True), 
     Column('value', String(100)), 
    ) 
meta.create_all() 

類(注意班上association_proxy):

class Note(object): 
    def __init__(self, name, value): 
     self.name = name 
     self.value = value 
class Item(object): 
    def __init__(self, name, description=''): 
     self.name = name 
     self.description = description 
    notes = association_proxy('_notesdict', 'value', creator=Note) 

映射:

mapper(Note, tb_notes) 
mapper(Item, tb_items, properties={ 
     '_notesdict': relation(Note, 
      collection_class=column_mapped_collection(tb_notes.c.name)), 
    }) 

然後只是測試它:

Session = sessionmaker(bind=engine) 
s = Session() 

i = Item('ball', 'A round full ball') 
i.notes['color'] = 'orange' 
i.notes['size'] = 'big' 
i.notes['data'] = 'none' 

s.add(i) 
s.commit() 
print i.notes 

,打印:

​​

但是,那些在附註表?

>>> print list(tb_notes.select().execute()) 
[(1, u'color', u'orange'), (1, u'data', u'none'), (1, u'size', u'big')] 

它的工作原理! :)

+0

那麼您如何刪除`i`呢?我得到一個`aise AssertionError(「依賴規則試圖在實例'%s''%(r,mapperutil.state_str(dest)))```時試圖清空主鍵列'%s'異常`s.delete i)` – Sardathrion 2011-11-24 12:48:13

-6

簡單的答案是'不'。

SQLAlchemy是SQL數據庫的包裝。

您引用的關係示例將SQL表之間的關係轉換爲Python類似於映射的結構,以使SQL SELECT語句和查找另一個表中的行變得更簡單。

item.notes['color'] = Note('color', 'blue') 

是必需的,因爲Note是具有兩列的單獨的表。你不能離開Note部分。

您必須定義這個其他SQL表,並且您必須創建映射到該SQL表的對象。