sqlalchemy 动态映射 [英] sqlalchemy dynamic mapping

查看:52
本文介绍了sqlalchemy 动态映射的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有以下问题:

我有课:

<预><代码>类字(对象):def __init__(self):self.id = 无self.columns = {}def __str__(self):返回 "(%s, %s)" % (str(self.id), str(self.columns))

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

<预><代码>wordColumns = ['english', 'korean', 'romanian']

<预><代码>wordTable = Table('word', metadata,列('id',整数,primary_key = True))对于 wordColumns 中的 columnName:wordTable.append_column(Column(columnName, String(255), nullable = False))

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

<预><代码>映射器属性 = {}对于 wordColumns 中的列:mapperProperties['columns[\'%']' % column] = wordTable.columns[column]映射器(Word,wordTable,mapperProperties)

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

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

我不得不说,我在 Python 和 SQLAlchemy 方面的经验非常有限,可能无法做我想做的事情.

感谢任何帮助,

提前致谢.

解决方案

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

考虑以下设置:

from sqlalchemy import Table, Column, Integer, Unicode, MetaData, create_engine从 sqlalchemy.orm 导入映射器,create_session类字(对象):通过wordColumns = ['english', 'korean', 'romanian']e = create_engine('sqlite://')元数据 = 元数据(绑定 = e)t = Table('words', metadata, Column('id', Integer, primary_key=True),*(Column(wordCol, Unicode(255)) for wordCol in wordColumns))metadata.create_all()映射器(字,t)session = create_session(bind=e, autocommit=False, autoflush=True)

使用该空类,您可以执行以下操作:

w = Word()w.english = 你的名字w.korean = u'이름'w.romanian = u'nume'session.add(w)session.commit()

当你想访问数据时:

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

这就是整个sqlalchemy的ORM点,而不是使用tupledict来访问数据,您在自己的类中使用类似属性的访问权限.

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

language = '韩文'打印 getattr(w, 语言)

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

<小时>

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

你可以在 Word 类上做到:

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

其余的设置工作如上.然后你可以像这样使用它:

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

如果你想要一个 columns 属性,那么你需要一个 dict-like

class AttributeDict(DictMixin):def __init__(self, obj):self._obj = objdef __getitem__(self, item):返回 getattr(self._obj, item)def __setitem__(self, item, value):返回 setattr(self._obj, item, value)类字(对象):def __init__(self):self.columns = AttributeDict(self)

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

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

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

I have the following problem:

I have the class:


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 is a dict which will hold (columnName:columnValue) values. The name of the columns are known at runtime and they are loaded in a wordColumns list, for example


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))

I even created a explicit mapper properties to "force" the table columns to be mapped on word.columns[columnName], instead of word.columnName, I don't get any error on mapping, but it seems that doesn't work.


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

mapper(Word, wordTable, mapperProperties)

When I load a word object, SQLAlchemy creates an object which has the word.columns['english'], word.columns['korean'] etc. properties instead of loading them into word.columns dict. So for each column, it creates a new property. Moreover word.columns dictionary doesn't even exists.

The same way, when I try to persist a word, SQLAlchemy expects to find the column values in properties named like word.columns['english'] (string type) instead of the dictionary word.columns.

I have to say that my experience with Python and SQLAlchemy is quite limited, maybe it isn't possible to do what I'm trying to do.

Any help appreciated,

Thanks in advance.

解决方案

It seems that you can just use the attributes directly instead of using the columns dict.

Consider the following setup:

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)

With that empty class you can do:

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

session.add(w)
session.commit()

And when you want to access the data:

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

That's the whole sqlalchemy's ORM point, instead of using a tuple or dict to access the data, you use attribute-like access on your own class.

So I was wondering for reasons you'd like to use a dict. Perhaps it's because you have strings with the language names. Well, for that you could use python's getattr and setattr instead, as you would on any python object:

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

That should solve all of your issues.


That said, if you still want to use dict-like access to the columns, it is also possible. You just have to implement a dict-like object. I will now provide code to do this, even though I think it's absolutely unnecessary clutter, since attribute access is so clean. If your issue is already solved by using the method above, don't use the code below this point.

You could do it on the Word class:

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

The rest of the setup works as above. Then you could use it like this:

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

If you want a columns attribute then you need a dict-like

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)

Then you could use as you intended:

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

I think you'll agree that all this is unnecessarly complicated with no added benefit.

这篇关于sqlalchemy 动态映射的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆