2009-04-23 49 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表的对象。