python - sqlalchemy 动态映射

标签 python sqlalchemy

我有以下问题:

我有课:


class Word(object):

    def __init__(self):
        self.id = None
        self.columns = {}

    def __str__(self):
        return "(%s, %s)" % (str(self.id), str(self.columns))

self.columns 是一个包含 (columnName:columnValue) 值的字典。列的名称在运行时是已知的,并且它们被加载到 wordColumns 列表中,例如


wordColumns = ['english', 'korean', 'romanian']

wordTable = Table('word', metadata,
                  Column('id', Integer, primary_key = True)
                  )
for columnName in wordColumns:
    wordTable.append_column(Column(columnName, String(255), nullable = False))

我什至创建了一个显式映射器属性来“强制”将表列映射到 word.columns[columnName],而不是 word.columnName,我在映射时没有收到任何错误,但似乎没有不工作。


mapperProperties = {}
for column in wordColumns:
    mapperProperties['columns[\'%']' % column] = wordTable.columns[column]

mapper(Word, wordTable, mapperProperties)

当我加载一个单词对象时,SQLAlchemy 会创建一个具有 word.columns['english']、word.columns['korean'] 等属性的对象,而不是将它们加载到 word.columns dict 中。因此,对于每一列,它都会创建一个新属性。而且 word.columns 字典甚至不存在。

同样,当我尝试持久化一个词时,SQLAlchemy 期望找到列值 在名为 word.columns['english'](字符串类型)而不是字典 word.columns 的属性中。

我不得不说,我对 Python 和 SQLAlchemy 的经​​验非常有限,也许无法完成我想做的事情。

感谢任何帮助,

提前致谢。

最佳答案

看来你可以直接使用属性而不是使用columns dict

考虑以下设置:

from sqlalchemy import Table, Column, Integer, Unicode, MetaData, create_engine
from sqlalchemy.orm import mapper, create_session

class Word(object):
    pass

wordColumns = ['english', 'korean', 'romanian']
e = create_engine('sqlite://')
metadata = MetaData(bind=e)

t = Table('words', metadata, Column('id', Integer, primary_key=True),
    *(Column(wordCol, Unicode(255)) for wordCol in wordColumns))
metadata.create_all()
mapper(Word, t)
session = create_session(bind=e, autocommit=False, autoflush=True)

有了那个空类你可以做:

w = Word()
w.english = u'name'
w.korean = u'이름'
w.romanian = u'nume'

session.add(w)
session.commit()

以及当您想要访问数据时:

w = session.query(Word).filter_by(english=u'name').one()
print w.romanian

这就是整个sqlalchemy的ORM点,而不是使用tupledict来访问数据,您可以对自己的类使用类属性访问。

所以我想知道您想使用 dict 的原因。也许是因为您有带有语言名称的字符串。好吧,为此你可以使用 python 的 getattrsetattr,就像你在任何 python 对象上一样:

language = 'korean'
print getattr(w, language)

这应该可以解决您所有的问题。


也就是说,如果您仍想使用类似dict 的方式访问列,也是可以的。您只需要实现一个类似于 dict 的对象。我现在将提供执行此操作的代码,尽管我认为这绝对是不必要的困惑,因为属性访问非常简洁。如果您的问题已通过上述方法解决,请不要使用此时下方的代码。

您可以在 Word 类上执行此操作:

class Word(object):
    def __getitem__(self, item): 
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)

其余设置的工作方式与上述相同。然后你可以像这样使用它:

w = Word()
w['english'] = u'name'

如果你想要一个 columns 属性,那么你需要一个类似 dict

class AttributeDict(DictMixin):
    def __init__(self, obj):
        self._obj = obj
    def __getitem__(self, item):
        return getattr(self._obj, item)
    def __setitem__(self, item, value):
        return setattr(self._obj, item, value)

class Word(object):
    def __init__(self):
        self.columns = AttributeDict(self)

然后你可以按你的意图使用:

w = Word()
w.columns['english'] = u'name' 

我想您会同意,所有这些都不必要地复杂化了,而且没有任何额外好处。

关于python - sqlalchemy 动态映射,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2574105/

相关文章:

python - isinstance(object, type) 给了我一个错误 - 另外,展平嵌套列表

python - 如何将 execution_date 作为纪元时间?

python - 如何告诉 tox 使用 PyPI 镜像来安装包?

python - SQLAlchemy 查找两个日期之间的行,包括给定的结束日期

sql - 使用Flask-SQLAlchemy进行多对多查询

python - 为什么我的 alembic 迁移有问题

python - 更改 Path PosixPath 对象中的文件名前缀

Python 如何在数组中创建数组?

python - SQLAlchemy 尝试两次删除多对多次要关系

python - SQLAlchemy 和标量值