是否有一种简单的方法来“解除”来自sqlalchemy的ORM的实例化类,即将其转换为常规对象?
即,假设我有一个映射到工作表的Worker类:
class Worker(object):
def earnings(self):
return self.wage*self.hours
mapper(Worker,workers)
其中,工人是包含大量观察结果的反映表。我想这样做的原因是像worker.earnings()这样的方法非常慢,因为所有sqlalchemy开销(我的应用程序不需要)。例如,如果self.wage属于普通级别的财产,那么访问self.wage的速度要慢10倍。
答案 0 :(得分:5)
如果你需要永久地解除一个类,只需处理映射器:
sqlalchemy.orm.class_mapper(Worker).dispose()
SQLAlchemy检测作为类对象的属性描述符。因此,如果您需要单独的deinstrumented版本的对象,则需要创建一个类的版本,该类在其类型层次结构中没有描述符。
一种好方法是为每个模型类创建一个持久子类,并为持久化类创建映射器。这是一个类装饰器,它为您创建子类,并将其作为类属性添加到原始类:
def deinstrumentable(cls):
"""Create a deinstrumentable subclass of the class."""
def deinstrument(self):
"""Create a non-instrumented copy of the object."""
obj = cls.__new__(cls)
obj.__dict__.update(self.__dict__)
del obj._sa_instance_state
return obj
persistent = type('Persisted%s' % cls.__name__, (cls,), {
'Base': cls,
'deinstrument': deinstrument
})
return persistent
你可以在这样的定义中使用它:
@deinstrumentable
class Worker(object):
def earnings(self):
return self.wage*self.hours
mapper(Worker, workers)
当你有一个持久对象时,你可以像这样创建一个denstrumented版本:
worker = session.query(Worker).first()
detached_worker = worker.deinstrument()
您可以直接创建一个denstrumented版本:
detached_worker = Worker.Base()
答案 1 :(得分:0)
如果你知道你想要的字段的名称,比如说你有一个名为fields
的字符串列表,以及你想要的那些方法,例如你的例子中的earnings
,名为methods
的字符串列表,然后:
def deinstrument(obj, fields, methods):
cls = type(obj)
class newcls(object): pass
newobj = newcls()
for f in fields:
setattr(newobj, f, getattr(obj, f))
for m in methods:
setattr(newcls, m, getattr(cls, m).im_func)
return newobj
您可能希望__name__
字符串中包含fields
,以便新对象的类与您“去除仪器”的名称相同。