python - 为 SQLAlchemy 多对多数据库设置关系/映射

标签 python orm sqlalchemy

我是 SQLAlchemy 和关系数据库的新手,我正在尝试为带注释的词典建立模型。我想支持可以在运行时添加或删除的单词的任意数量的键值注释。由于键名会有很多重复,所以我不想使用 this solution直接,尽管代码相似。

我的设计有文字对象和属性对象。单词和属性存储在单独的表中,并通过 property_values 表链接这两个表。代码如下:

from sqlalchemy import Column, Integer, String, Table, create_engine
from sqlalchemy import MetaData, ForeignKey
from sqlalchemy.orm import relation, mapper, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///test.db', echo=True)
meta = MetaData(bind=engine)

property_values = Table('property_values', meta,
    Column('word_id', Integer, ForeignKey('words.id')),
    Column('property_id', Integer, ForeignKey('properties.id')),
    Column('value', String(20))
)
words = Table('words', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(20)),
    Column('freq', Integer)
)
properties = Table('properties', meta,
    Column('id', Integer, primary_key=True),
    Column('name', String(20), nullable=False, unique=True)
)
meta.create_all()

class Word(object):
    def __init__(self, name, freq=1):
        self.name = name
        self.freq = freq

class Property(object):
    def __init__(self, name):
        self.name = name
mapper(Property, properties)  

现在我希望能够执行以下操作:

Session = sessionmaker(bind=engine)
s = Session()
word = Word('foo', 42)
word['bar'] = 'yes' # or word.bar = 'yes' ?
s.add(word)
s.commit()

理想情况下,应将 1|foo|42 添加到 Words 表,将 1|bar 添加到属性表,然后添加 1|1|yes 到 property_values 表。但是,我没有正确的映射和关系来实现这一点。我通过阅读 http://www.sqlalchemy.org/docs/05/mappers.html#association-pattern 的文档得到了这种感觉。我想在这里使用关联代理或类似的东西,但我不清楚语法。我尝试过这个:

mapper(Word, words, properties={
    'properties': relation(Property, secondary=property_values)
    })

但是这个映射器只填充外键值,我还需要填充其他值。任何帮助将不胜感激。

最佳答案

只需使用 Dictionary-Based Collections mapping映射 - 针对您的问题的开箱即用的解决方案。摘自链接:

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')
print item.notes['color']

或者尝试 Inserting data in Many to Many relationship in SQLAlchemy 的解决方案。显然,您必须将 list 逻辑替换为 dict 逻辑。
请问题作者使用 associationproxy 发布他的最终代码,他提到他最终使用了该代码。

关于python - 为 SQLAlchemy 多对多数据库设置关系/映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2316537/

相关文章:

python - SQLAlchemy:@property 映射?

python - 如何读取一整行,然后只读取最后五个字符?

python - Mongoengine查询列表字段包含字符串匹配

inheritance - ORM 继承

php - Eloquent - 从登录用户获取特定列

python - 如何在 sqlalchemy 中连接两个关于公共(public)关系的查询?

flask - 在 Flask 中分配组权限

javascript - Python Selenium 或常规 Javascript,选择伪下拉列表的列表元素选项?

python - 在Python中识别列表列表中的峰值海拔

java - JPA 2.0 中的 session 和事务有什么区别?