我正在使用flask +棉花糖+ sqlalchemy。
我需要:
发送包含以下内容的http请求:
{
"first_name": "John"
"last_name": "Doe"
"gender": "male"
}
并将该值保存为一个整数在数据库中,0
表示男性,1
表示女性。
我设法通过实现自定义棉花糖字段并将sqlalchemy模型中的字段更改为Integer
而不是Enum
字段来解决这个问题。这确实有一个缺点,即从数据库中检索到的性别不能与这个自定义棉花糖GenderField
序列化。
from marshmallow.fields import Field
class GenderField(Field):
def _serialize(self, value, attr, obj, **kwargs):
return value.value if value is not None else ''
def _deserialize(self, value, attr, data, **kwargs):
options = [e.value for e in Genders]
genders = {val: i for i, val in enumerate(options)}
try:
return genders[value]
except KeyError as err:
raise ValidationError(f'Value must be one of: {options}')
编辑:将棉花糖字段与sqlalchemyTypeDecorator
相结合是我更喜欢的另一个解决方案。通过这种方式,我们将用于棉花糖模式的字符串分割为enum元组中的第二个值,第一个值(int)进入db,整个类型作为flask应用的enum来处理。
class Gender(Enum):
MALE = 0, 'male'
FEMALE = 1, 'female'
class TupleEnum(TypeDecorator):
impl = Integer
@property
def python_type(self):
return type(self.enum_type)
def __init__(self, enum_type, *args, **kwargs):
super().__init__(*args, **kwargs)
self.enum_type = enum_type
def process_bind_param(self, value: Enum, dialect):
return value.value[0]
def process_result_value(self, value: int, dialect):
options = {e.value[0]: e for e in self.enum_type}
return options[value]
def process_literal_param(self, value: int, dialect):
return self.process_bind_param(value, dialect)
SQLAlchemy将枚举保存为字符串,而不是整数1,因此如果需要在数据库中使用整数,则不能使用Enum
。默认情况下,使用的字符串是成员名,但您可以指定一个函数来使用值…已转换为字符串。
- SQLAlchemy enum docs