Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to sqlalchemy mapping class non db attributes

The app has such logic: list of people stored in the database, each man has a rating calculated in realtime and this value is never stored in database. And I want to use one class to work with dababase fields: name, age etc. and non database field: rating.

Is it possible in sqlalchemy? Now I'm using inheritance Man -> ManMapping:

class Man:
  rating = None

  def get_rating(self):
    return self.rating

  ...

class ManMapping(Base, Man):
  __tablename__ = 'man'
  id = Column('man_id', Integer, primary_key=True)
  name = Column(Unicode)

  ...

It works but it looks terrible for me. Is it right approach or I have to do something else?

like image 557
Serge Avatar asked May 30 '17 19:05

Serge


1 Answers

This is the correct solution: https://docs.sqlalchemy.org/en/13/orm/constructors.html Hybrid properties are somewhat less flexible that this. The accepted answer is not an actual answer to the problem.

The SQLAlchemy ORM does not call init when recreating objects from database rows. The ORM’s process is somewhat akin to the Python standard library’s pickle module, invoking the low level new method and then quietly restoring attributes directly on the instance rather than calling init.

If you need to do some setup on database-loaded instances before they’re ready to use, there is an event hook known as InstanceEvents.load() which can achieve this; it is also available via a class-specific decorator called reconstructor(). When using reconstructor(), the mapper will invoke the decorated method with no arguments every time it loads or reconstructs an instance of the class. This is useful for recreating transient properties that are normally assigned in init:

from sqlalchemy import orm

class MyMappedClass(object):
    def __init__(self, data):
        self.data = data
        # we need stuff on all instances, but not in the database.
        self.stuff = []

    @orm.reconstructor
    def init_on_load(self):
        self.stuff = []
like image 118
zeller Avatar answered Sep 23 '22 08:09

zeller