【问题标题】:SQLAlchemy - Dictionary of tagsSQLAlchemy - 标签字典
【发布时间】:2010-10-21 07:32:35
【问题描述】:

我对 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 中可以吗?

谢谢

【问题讨论】:

    标签: python sqlalchemy


    【解决方案1】:

    简单的答案是是的

    只需使用关联代理:

    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
    

    打印出来的:

    {u'color': u'orange', u'data': u'none', u'size': u'big'}
    

    但是,那些在笔记表里吗?

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

    有效!! :)

    【讨论】:

    • 那你怎么删除i呢?尝试s.delete(i) 时出现aise AssertionError("Dependency rule tried to blank-out primary key column '%s' on instance '%s'" % (r, mapperutil.state_str(dest))) 异常
    • 回答我自己的问题:In mapper(item [...], cascade="all, delete-orphan"), [...]
    【解决方案2】:

    简单的答案是“不”。

    SQLAlchemy 是 SQL 数据库的包装器。

    您引用的关系示例将 SQL 表之间的关系转换为类似于 Python 映射的结构,以使执行 SQL SELECT 语句和在另一个表中定位行变得更加简单。

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

    是必不可少的,因为Note 是一个包含两列的单独表。你不能离开Note 部分。

    您必须定义这个其他 SQL 表,并且必须创建映射到该 SQL 表的对象。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2010-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多