"De-tool" - an instance of an object from sqlalchemy ORM

Is there a simple β€œde-tool” way to instantiate a class coming from sqlalchemy ORM, i.e. turn it into a regular object?

Ie, suppose I have a Worker class mapped to a workers table:

class Worker(object): def earnings(self): return self.wage*self.hours mapper(Worker,workers) 

where workers are a reflected table containing many observations. The reason I want to do this is because methods like worker.earnings () are very slow due to all sqlalchemy overhead (which I don't need for my application). For example, accessing self.wage is about 10 times slower than if self.wage was a property of a regular class.

+4
source share
2 answers

If you need to constantly de-instruct the class, simply remove the cartographer:

 sqlalchemy.orm.class_mapper(Worker).dispose() 

The SQLAlchemy toolkit lives like property descriptors of a class object. Therefore, if you need separate, de-instrumented versions of objects, you need to create a version of the class that does not have descriptors in the type hierarchy.

A good way would be to have a constant subclass for each class of the model and create markers for the constant classes. Here's a class decorator that subclasses for you and adds it as a class attribute in the original:

 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 

You would use it in the definition as follows:

 @deinstrumentable class Worker(object): def earnings(self): return self.wage*self.hours mapper(Worker, workers) 

And when you have a permanent object, you can create its version with de-instrumentation as follows:

 worker = session.query(Worker).first() detached_worker = worker.deinstrument() 

You can create a deinstrumented version directly as follows:

 detached_worker = Worker.Base() 
+5
source

If you know the names of the fields you want, say that you have them in the list of strings called fields , and those that you want, for example earnings in your example, in the list of strings called methods , then:

 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 

You will probably want __name__ among the fields strings, so the new class of the object will have the same name as yours, a "de-tool".

0
source

Source: https://habr.com/ru/post/1301079/


All Articles