python - 使用flask + marshmallow + sqlalachemy 发送枚举值并将它们保存到数据库?
问题描述
我正在使用烧瓶 + 棉花糖 + sqlalchemy。
我必须:
要发送包含此内容的 http 请求:
{
"first_name": "John"
"last_name": "Doe"
"gender": "male"
}
并将值作为整数保存在数据库中,无论0
是男性还是1
女性。
ID | 名 | 姓 | 性别 |
---|---|---|---|
42 | 约翰 | 能源部 | 0 |
到目前为止的路:
要求.txt
...
Flask==2.0.1
flask-marshmallow==0.14.0
Flask-SQLAlchemy==2.5.1
marshmallow==3.13.0
marshmallow-enum==1.5.1
marshmallow-sqlalchemy==0.26.1
SQLAlchemy==1.4.22
...
架构.py
from .models import Users, Genders
from .extensions import ma
class SignUpSchema(ma.SQLAlchemySchema):
class Meta:
model = Users
first_name = ma.auto_field(data_key='firstName', required=True)
last_name = ma.auto_field(data_key='lastName', required=True)
gender = EnumField(enum=Genders, required=True)
视图.py
from flask import request
from flask.views import MethodView
from .schemas import SignUpSchema
from .models import Users, Genders
from .extensions import db
class SignUp(MethodView):
methods = ['POST']
def post(self):
json_data = request.get_json()
schema = SignUpSchema()
data = schema.load(json_data)
user = Users(**data)
db.session.add(user)
db.session.commit()
return {'id': user.id}
模型.py
import enum
from sqlalchemy import Column,Integer, String, Enum
from .extensions import db
class Genders(enum.Enum):
MALE = "male"
FEMALE = "female"
class Users(db.Model):
id = Column(Integer, primary_key=True)
first_name = Column(String(100))
last_name = Column(String(100))
gender = Column(Enum(Genders))
当前状态:
{
"firstName": "john",
"lastName": "doe",
"gender": "MALE"
}
ID | 名 | 姓 | 性别 |
---|---|---|---|
42 | 约翰 | 母鹿 | 男性 |
我只是不知道如何更改请求和数据库插入中的枚举值。
解决方案
我设法通过实现自定义棉花糖字段并将 sqlalchemy 模型中的字段更改为Integer
而不是Enum
字段来解决该问题。这确实有一个缺点,即无法使用此自定义 marshmallow 序列化从数据库中检索到的性别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}')
编辑:
将棉花糖字段与 sqlalchemy 相结合TypeDecorator
是我更喜欢的另一个解决方案。这样,我们将字符串拆分为棉花糖模式作为枚举元组中的第二个值,第一个值(int)进入数据库,整个类型作为烧瓶应用程序的枚举处理。
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)
推荐阅读
- javascript - Vuejs - 提交属性时的 Vuex 行为
- java - RxJava call the network when database is empty
- angularjs - One way binding doesn't work in AngularJS with setInterval
- javascript - Sequelize Deprecated Error Message when running migration
- angular - Angular 5 HttpClient 无法填充变量文本
- java - 如何为 KeyPair 生成生成确定性 SecureRandom?
- javascript - 如何将 PhantomJS 添加到我的 Chrome 扩展程序中?
- ios - Background color of UIView defaults to black, trying to change programmatically in swift 4
- sql - 将 MS Access 查询转换为 SQL Server 查询
- video - ffmpeg - 如何在保留总帧数的同时缩放视频?