Как сохранить перечисление Python с помощью Pony ORM?
скажем, у меня есть этот простой маленький пони ОРМ отображение здесь. Встроенные классы в 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 не поддерживает отображение типа перечисления. Конечно, обходной путь здесь - просто сохранить значение перечисления и предоставить геттер в классе StateTable для преобразования значения в перечисление еще раз. Но это утомительно и подвержено ошибкам. Я могу также просто используйте другой ORM. Возможно, я буду, если эта проблема станет слишком большой головной болью. Но я лучше останусь с пони, если смогу.
Я бы предпочел создать конвертер базы данных для хранения перечисления, как намекает сообщение об ошибке. Кто-нибудь знает, как это сделать?
обновление: Благодаря помощи Итана я пришел к следующему решению.
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))
1 ответов
выдержка из какого-то случайного списка рассылки:
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"
вы можете изучить код существующих конвертеров, чтобы увидеть, как эти методы реализуются.