sqlalchemy动态映射

Ale*_*x D 12 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))
Run Code Online (Sandbox Code Playgroud)

self.columns是一个dict,它将保存(columnName:columnValue)值.列的名称在运行时是已知的,例如,它们被加载到wordColumns列表中


wordColumns = ['english', 'korean', 'romanian']
Run Code Online (Sandbox Code Playgroud)

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

我甚至创建了一个显式映射器属性来"强制"表格列映射到word.columns [columnName],而不是word.columnName,我没有得到任何映射错误,但它似乎不起作用.


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

mapper(Word, wordTable, mapperProperties)
Run Code Online (Sandbox Code Playgroud)

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

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

我不得不说我对Python和SQLAlchemy的经验非常有限,也许我不可能做我想做的事情.

任何帮助,赞赏,

提前致谢.

nos*_*klo 32

看来你可以直接使用属性而不是使用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)
Run Code Online (Sandbox Code Playgroud)

有了这个空课,你可以做:

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

session.add(w)
session.commit()
Run Code Online (Sandbox Code Playgroud)

当您想要访问数据时:

w = session.query(Word).filter_by(english=u'name').one()
print w.romanian
Run Code Online (Sandbox Code Playgroud)

这是整个sqlalchemyORM点,而不是使用tupledict访问数据,您在自己的类上使用类似属性的访问.

所以我想知道你想要使用的原因dict.也许是因为你有语言名字的字符串.那么,你可以使用python getattr,setattr而不是像任何python对象一样:

language = 'korean'
print getattr(w, language)
Run Code Online (Sandbox Code Playgroud)

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


也就是说,如果您仍然希望使用dict类似的访问列,也可以.你只需要实现一个类似dict的对象.我现在将提供代码来执行此操作,即使我认为这绝对是不必要的混乱,因为属性访问是如此干净.如果您的问题已通过上述方法解决,请不要使用此点下方的代码.

你可以在Word课堂上做到:

class Word(object):
    def __getitem__(self, item): 
        return getattr(self, item)
    def __setitem__(self, item, value):
        return setattr(self, item, value)
Run Code Online (Sandbox Code Playgroud)

其余设置如上所述.然后你可以像这样使用它:

w = Word()
w['english'] = u'name'
Run Code Online (Sandbox Code Playgroud)

如果你想要一个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)
Run Code Online (Sandbox Code Playgroud)

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

w = Word()
w.columns['english'] = u'name' 
Run Code Online (Sandbox Code Playgroud)

我想你会同意所有这些都是不必要的复杂,没有额外的好处.

  • 我无法理解这里有多少这样的帖子,但是当我看到一个帖子时我还是很敬畏.感谢您对此深思熟虑.一年后,新人们仍然乐于助人.祝贺你 (3认同)
  • 感谢您抽出宝贵时间撰写如此完整的答案.我同意第一种解决方案比第二种更清洁,更优雅.我没有任何充分的理由使用dict,除了这是我心中的"正常"事实.就像我之前说过的,我是Python的新手,我还没有学会利用动态语言的好处.我将使用您的第一个解决方案.再次感谢 :) (2认同)