【问题标题】:How can I store a Python Enum using Pony ORM?如何使用 Pony ORM 存储 Python 枚举?
【发布时间】:2015-10-02 10:38:09
【问题描述】:

假设我在这里有这个简单的小 Pony 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 值,并在 Class StateTable 中提供一个 getter 以再次将值转换为 Enum。但这是乏味且容易出错的。我也可以只使用另一个 ORM。如果这个问题变得太令人头疼,也许我会。但如果可以的话,我宁愿坚持使用 Pony。

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

更新: 感谢 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))

【问题讨论】:

    标签: python python-3.x orm enums ponyorm


    【解决方案1】:

    Excerpt from some random mailing list:

    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"
    

    你可以研究一下现有转换器的代码,看看这些方法如何 已实施。

    【讨论】:

    • 谢谢!我以前看过那个帖子,但我认为这是关于添加 SQL 类型,而不是 python 类型。我更新了我的问题以展示我想出的解决方案。
    猜你喜欢
    • 1970-01-01
    • 2010-09-20
    • 2013-04-13
    • 2019-05-09
    • 2018-06-14
    • 1970-01-01
    • 2016-11-10
    • 2021-12-28
    • 1970-01-01
    相关资源
    最近更新 更多