如何使用Pony ORM存储Python Enum ?



假设这里有一个简单的小马ORM映射。内置Enum类是Python 3.4的新功能,并向后移植到2.7。

from enum import Enum
from pony.orm import Database, Required

class State(Enum):
    ready = 0
    running = 1
    errored = 2
if __name__ == '__main__':
    db = Database('sqlite', ':memory:', create_db=True)
    class StateTable(db.Entity):
        state = Required(State)
    db.generate_mapping(create_tables=True)

当我运行程序时,抛出一个错误。

TypeError: No database converter found for type <enum 'State'>

这是因为Pony不支持映射枚举类型。当然,这里的解决方法是仅存储Enum值,并在classstatetable中提供getter以再次将值转换为Enum。但这很繁琐,而且容易出错。我也可以用另一个ORM。如果这个问题变得太让人头疼的话,也许我会的。但如果可以的话,我宁愿和小马在一起。

我宁愿创建一个数据库转换器来存储枚举,就像错误消息所暗示的那样。有人知道怎么做吗?

更新:在Ethan的帮助下,我想出了以下解决方案。

from enum import Enum
from pony.orm import Database, Required, db_session
from pony.orm.dbapiprovider import StrConverter

class State(Enum):
    ready = 0
    running = 1
    errored = 2
class EnumConverter(StrConverter):
    def validate(self, val):
        if not isinstance(val, Enum):
            raise ValueError('Must be an Enum.  Got {}'.format(type(val)))
        return val
    def py2sql(self, val):
        return val.name
    def sql2py(self, value):
        # Any enum type can be used, so py_type ensures the correct one is used to create the enum instance
        return self.py_type[value]
if __name__ == '__main__':
    db = Database('sqlite', ':memory:', create_db=True)
    # Register the type converter with the database
    db.provider.converter_classes.append((Enum, EnumConverter))
    class StateTable(db.Entity):
        state = Required(State)
    db.generate_mapping(create_tables=True)
    with db_session:
        s = StateTable(state=State.ready)
        print('Got {} from db'.format(s.state))

节选自一些随机邮件列表:

2.2。转换器的方法

每个转换器类应该定义以下方法:

class MySpecificConverter(Converter):
    def init(self, kwargs):
        # Override this method to process additional positional
        # and keyword arguments of the attribute
       if self.attr is not None:
            # self.attr.args can be analyzed here
            self.args = self.attr.args
        self.my_optional_argument = kwargs.pop("kwarg_name")
        # You should take all valid options from this kwargs
        # What is left in is regarded as unrecognized option
    def validate(self, val):
        # convert value to the necessary type (e.g. from string)
        # validate all necessary constraints (e.g. min/max bounds)
        return val
    def py2sql(self, val):
        # prepare the value (if necessary) to storing in the database
        return val
    def sql2py(self, value):
        # convert value (if necessary) after the reading from the db
        return val
    def sql_type(self):
        # generate corresponding SQL type, based on attribute options
        return "SOME_SQL_TYPE_DEFINITION"

您可以研究现有转换器的代码,以了解这些方法如何实现。

最新更新