16

ここに、この単純で小さな 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 値を格納し、値を再度 Enum に変換するクラス StateTable に getter を提供することです。しかし、これは面倒でエラーが発生しやすくなります。別の 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))
4

1 に答える 1

12

いくつかのランダムなメーリング リストからの抜粋:

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"

既存のコンバーターのコードを調べて、これらのメソッドがどのように実装されているかを確認できます。

于 2015-07-14T01:34:40.343 に答える