SQLAlchemy:如何将通用映射逻辑添加到我的自定义基类(使用声明式样式映射)?

时间:2014-07-18 01:15:50

标签: python sqlalchemy

我有一个项目,其中每个表都有一些共同的字段,例如状态,我想为所有字段添加别名。是否可以在不手动为每个类添加别名的情况下执行此操作?例如,这是我现在所拥有的:

from core import foo_table, bar_table, Status 

Base = declarative_base()

def CustomBase(object):
   @property
   def status(self):
      return Status(self._status)
  ...

def Foo(Base, CustomBase):
   __table__ = foo_table
   _status = foo_table.c.status
   ...


def Bar(Base, CustomBase):
   __table__ = bar_table
   _status = bar_table.c.status
   ...

理想情况下,我希望能够在CustomBase上而不是在Foo和Bar中设置我的_status别名,或者设置我的项目,以便在加载扩展CustomBase的类时添加别名。这是可能的还是我试图以错误的方式实现这一目标?我知道如果我在我的数据库中重命名状态字段或重命名CustomBase中的status属性,我可以使它工作,但我希望尽可能避免这种情况,因为它们都是同一事物的表示,并且无需通过代码直接访问枚举值。

谢谢!

1 个答案:

答案 0 :(得分:1)

您最好的选择可能是创建一个自定义列类型,以使Enum适应您自己的Status类的转换。有关完整参考,请参阅here。以下是core模块的草稿,准确的代码取决于您的情况。

# core module

import sqlalchemy.types as types

class DBStatus (types.TypeDecorator):

    impl = types.Enum

    # what should happen with Status objects on the way into the table
    def process_bind_param(self, value, dialect):
        if value is None:
            return value
        return str(value)  # if Status has a __str__ or __repr__ method

    # what should happen with Enum objects on the way out of the table
    def process_result_value(self, value, dialect):
        if value is None:
            return value
        return Status(value)

foo_table = Table(
    'foo',
    MetaData(),
    Column('status', DBStatus('OK', 'Error')),
    # ...
)

在此之后,您不必再使用映射在模块中执行任何特殊操作:

# module with the mappings

Base = declarative_base()

class Foo (Base):
    __table__ = foo_table
    # ...

事实上,就状态列而言,你可以直接使用完整的声明性映射。

# everything in one module

class DBStatus (types.TypeDecorator):

    # same as above

Base = declarative_base()

class Foo (Base):
    status = Column(DBStatus('OK', 'Error'))
    # ...