添加到 sqlalchemy 映射类的非数据库属性

Ser*_*rge 8 python sqlalchemy

该应用程序具有这样的逻辑:存储在数据库中的人员列表,每个人都有一个实时计算的评分,这个值永远不会存储在数据库中。我想使用一个类来处理 dababase 字段:姓名、年龄等和非数据库字段:评级。

在 sqlalchemy 中可能吗?现在我使用继承 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)

  ...
Run Code Online (Sandbox Code Playgroud)

它有效,但对我来说看起来很糟糕。这是正确的方法还是我必须做其他事情?

zel*_*ler 8

这是正确的解决方案:https://docs.sqlalchemy.org/en/13/orm/constructors.html \n混合属性的灵活性比这要差一些。接受的答案并不是问题的实际答案。

\n
\n

从数据库行重新创建对象时,SQLAlchemy ORM 不会调用init 。ORM\xe2\x80\x99s 过程有点类似于 Python 标准库\xe2\x80\x99s pickle 模块,调用低级new方法,然后直接在实例上悄悄恢复属性,而不是调用init

\n
\n
\n

如果您需要在数据库加载的实例\xe2\x80\x99 准备使用之前对其进行一些设置,可以使用名为 InstanceEvents.load() 的事件挂钩来实现此目的;它也可以通过称为reconstructor()的特定于类的装饰器来使用。当使用reconstructor()时,映射器将在每次加载或重建类的实例时调用不带参数的修饰方法。这对于重新创建通常在init中分配的瞬态属性非常有用:

\n
\n
from sqlalchemy import orm\n\nclass MyMappedClass(object):\n    def __init__(self, data):\n        self.data = data\n        # we need stuff on all instances, but not in the database.\n        self.stuff = []\n\n    @orm.reconstructor\n    def init_on_load(self):\n        self.stuff = []\n
Run Code Online (Sandbox Code Playgroud)\n


M07*_*M07 1

在我看来,你应该有两个不同的类。一种用于代码中的逻辑,另一种用于与数据库通信。

class Man(object):
    """This class is for your application"""
   def __init__(self, name, rating):
       # If the identifier is only used by the DB it should not be in this class
       self.name = name
       self.rating = rating

class ManModel(Base):
    """This model is only to communicate with the DB"""
    __tablename__ = 'man'
    id = Column('man_id', Integer, primary_key=True)
    name = Column(Unicode)
Run Code Online (Sandbox Code Playgroud)

您应该有一个提供程序,它使用ManModel对象对数据库进行查询,然后将结果映射到Man对象并将映射的数据返回给调用者。您的应用程序将仅使用Man对象,并且您的提供者将进行映射。像下面这样:

class DbProvider(object):
    def get_man(self, id):
       man_model = session.query(ManModel).filter(ManModel.id == id).one_or_none()
       return self.man_mapper(man_model) if man_model else None

    def get_men(self):
        men_model = session.query(ManModel).all()
        return [self.man_mapper(man_model) for man_model in men_model]

    def man_mapper(self, man_model):
         return Man(man_model.name, self.calculate_rating(man_model))

 class Test(object):
      def display_man(self):
          man = db_provider.get_man(15)
          if man:
               print man.name, man.rating  
Run Code Online (Sandbox Code Playgroud)