vba34520
(XerCis)
2022 年8 月 11 日 02:36
1
代码
from enum import Enum
from apiflask import APIFlask
from apiflask.fields import Integer
from apiflask.validators import OneOf
app = APIFlask(__name__, docs_ui='elements')
class APIFlaskEnum(Enum):
@classmethod
def choices(cls):
return [i.value for i in cls]
@classmethod
def description(cls):
return '\n\n'.join(f'{i.value}={i.name}' for i in cls)
class CategoryEnum(APIFlaskEnum):
cat = 1
dog = 2
@app.get('/say')
@app.input(dict(
category=Integer(required=True, validate=OneOf(CategoryEnum.choices()))
), location='query')
@app.doc(description=CategoryEnum.description())
def say(data):
"""枚举值入参"""
return CategoryEnum(data['category']).name
if __name__ == '__main__':
app.run()
效果
以上为替代方案,但当参数有多个枚举类型时,该方案就不太适合了,有没有更优雅的方式解决呢?
还有一个是,要用两个\n才能显示出换行,有没有办法解决?
感谢!
greyli
(Grey Li)
2022 年8 月 13 日 04:05
2
优雅的方式可能是等 marshmallow 内置 Enum 支持的 PR 合并……
marshmallow-code:dev
← marshmallow-code:enum
opened 02:11PM - 20 Jul 22 UTC
Replaces @orenc17's #1885.
This is a long standing feature request. See for i… nstance discussions in #267.
The status quo is that people can use @justanr's [marshmallow_enum](https://github.com/justanr/marshmallow_enum).
Currently, this lib doesn't seem actively maintained. I don't blame the author. A few things are outdated, deprecated stuff. The changes since MA3 have been user contributed and some are still missing.
I'm thinking if we recommend this lib as the reference choice, why not integrate it in code? This is what I've been trying to do.
I started by importing the code and updating it for PY3/MA3.
I also removed the dump/load asymmetry (dump by value, load by name) that I found awkward and revamped the error message generation.
I was still not happy with the `by_value`/`by_name` mechanism. I serialize by name, so I could live with only this, but I understand the need for serializing by value (to get an int or a nicer string). However, I like the type to be well-defined so that we can inherit deserialization from basic fields, and to help documenting the type (e.g. in apispec).
My proposal is therefore an `Enum` field serializing by name, and typed enum fields `StringEnum` and `IntegerEnum`, to serialize by value with a given type. Users would be free to create new types but I believe those cover most cases.
Transition from `marshmallow_enum` should be relatively smooth for users who don't use the dump/load asymmetry and who don't rely on exact error messages.
This still lacks a bit of doc but I'd rather get feedback before polishing.
Note we can't use `OneOf` validator because validation occurs after deserialization and wrong values are caught at deserialization already.
「当参数有多个枚举类型时」具体是指什么?没太明白。
要用两个\n才能显示出换行
description 可以用 Markdown,不过也都差不多。另外或许可以考虑把这个放到字段的 description 里面:
category = Integer(
required = True,
validate = OneOf(CategoryEnum.choices()),
metadata = {'description': CategoryEnum.description()}
)
1 个赞
vba34520
(XerCis)
2022 年8 月 15 日 02:23
3
谢谢回复!希望 marshmallow 能早日添加这个 feature
理想的情况是,这样写就能生成参数为枚举值的文档:
@app.input(dict(
category=Integer(required=True, validate=OneOf(CategoryEnum))
), location='query')
vba34520
(XerCis)
2022 年8 月 15 日 02:43
4
根据建议优化了一下
from enum import Enum
from apiflask import APIFlask
from apiflask.fields import Integer
from apiflask.validators import OneOf
app = APIFlask(__name__, docs_ui='elements')
class APIFlaskEnum(Enum):
@classmethod
def choices(cls):
return [i.value for i in cls]
@classmethod
def description(cls):
desc = '<br>'.join(f'{i.value}={i.name}' for i in cls)
if cls.__doc__ and cls.__doc__ != 'An enumeration.':
desc = cls.__doc__ + '<br>' + desc
return desc
class CategoryEnum(APIFlaskEnum):
"""类别"""
cat = 1
dog = 2
@app.get('/say')
@app.input(dict(
category=Integer(required=True, validate=OneOf(CategoryEnum.choices()),
metadata={'description': CategoryEnum.description()})
), location='query')
def say(data):
"""枚举值入参"""
return CategoryEnum(data['category']).name
if __name__ == '__main__':
app.run()
效果
1 个赞
vba34520
(XerCis)
2022 年9 月 20 日 10:03
5
好消息!marshmallow 3.18.0 已更新枚举字段 marshmallow.fields.Enum
安装
pip install -U marshmallow
示例代码
from enum import Enum
from marshmallow import Schema, fields
class CategoryEnum(Enum):
cat = 1
dog = 2
class Pet:
def __init__(self, name, category):
self.name = name
self.category = category
class PetSchema(Schema):
name = fields.String()
category = fields.Enum(CategoryEnum)
class PetByValueSchema(Schema):
name = fields.String()
category = fields.Enum(CategoryEnum, by_value=True)
pet = Pet(name='Kitty', category=CategoryEnum.cat)
print(PetSchema().dump(pet))
print(PetByValueSchema().dump(pet))
# {'name': 'Kitty', 'category': 'cat'}
# {'name': 'Kitty', 'category': 1}
print(PetSchema().load({'name': 'Kitty', 'category': 'cat'}))
print(PetByValueSchema().load({'name': 'Kitty', 'category': 1}))
# {'name': 'Kitty', 'category': <CategoryEnum.cat: 1>}
# {'name': 'Kitty', 'category': <CategoryEnum.cat: 1>}
API 代码
import enum
from apiflask import APIFlask
from apiflask.fields import Integer
from marshmallow.fields import Enum
class CategoryEnum(enum.Enum):
"""类别"""
cat = 1
dog = 2
app = APIFlask(__name__, docs_ui='elements')
@app.get('/name')
@app.input(dict(
category=Enum(CategoryEnum)
), location='query')
def name(data):
return str(data['category'])
@app.get('/value')
@app.input(dict(
category=Enum(CategoryEnum, by_value=Integer)
), location='query')
def value(data):
return str(data['category'])
if __name__ == '__main__':
app.run()
1 个赞
greyli
(Grey Li)
2022 年9 月 25 日 13:44
6
试了一下,apispec 目前还没法正确为 Enum 字段解析 OpenAPI spec,估计还要等后续支持。
vba34520
(XerCis)
2022 年10 月 17 日 09:25
7
apispec 已更新枚举字段解析 enum2properties()
安装
pip install apispec==6.0.0
代码
from enum import Enum
from apispec import APISpec
from marshmallow import fields
from apispec.ext.marshmallow import MarshmallowPlugin
class MyEnum(Enum):
one = 1
two = 2
field = fields.Enum(MyEnum)
ma_plugin = MarshmallowPlugin()
spec = APISpec(title='', version='', openapi_version='3.0.3', plugins=(ma_plugin,))
ret = ma_plugin.converter.field2property(field)
print(ret)
# {'type': 'string', 'enum': 'one, two'}
1 个赞
vba34520
(XerCis)
2022 年10 月 18 日 01:23
9
试了一下不能直接渲染出来,如果辉哥有空麻烦看看,感谢
vba34520
(XerCis)
2022 年11 月 23 日 08:02
10
安装最新的 apispec 即可
pip install apispec -U
代码
import enum
from apiflask import APIFlask
from apiflask.fields import Integer
from marshmallow.fields import Enum
class CategoryEnum(enum.Enum):
"""类别"""
cat = 1
dog = 2
app = APIFlask(__name__, docs_ui='elements')
@app.get('/name')
@app.input(dict(
category=Enum(CategoryEnum)
), location='query')
def name(data):
return str(data['category'])
@app.get('/value')
@app.input(dict(
category=Enum(CategoryEnum, by_value=Integer)
), location='query')
def value(data):
return str(data['category'])
if __name__ == '__main__':
app.run()
效果
stutao
(Stutao)
2022 年12 月 1 日 02:15
11
有幸和题主经历了一样的问题,区别的是我的需求是在reponse中,经历了和题主一样的过程,很巧就看到这篇帖子,然后静静等待辉总1.2.0 的发布 。