【问题标题】:override default encoders for jsonable_encoder in FastAPI覆盖 FastAPI 中 jsonable_encoder 的默认编码器
【发布时间】:2020-06-10 19:14:38
【问题描述】:

我的代码使用Fast API:

class EnumTestT(Enum):
    test_t_value = 0

object = { 
    test: test_t_value
}

enum_mapping = {
    test_t_value: "Test"
}

def enum_encoder(val: EnumTestT) -> str:
    return enum_mapping[val]

custom_encoder = {
    EnumTestT: enum_encoder
}

@app.get("/test")
async def test_get():
    return jsonable_encoder(object, custom_encoder=custom_encoder)

问题在于jsonable_encoder 在默认值之后应用了自定义编码器。有什么方法可以在默认编码器之前应用它们。因为对于Enum 和任何派生类,报告的是枚举值而不是映射值。

【问题讨论】:

  • @lsabi 不确定我是否理解这个问题。
  • 我的意思是如果您需要链接中显示的东西。您可以返回您自己准备的响应,并且不会通过 jsonable_encoder
  • @lsabi 我有一个字典,我在代码中简单地表示了它。对象比较复杂,需要编码。因此,要么我自己编写一个完全自定义的编码器,我想避免或使用jsonable_encoder,但我似乎无法做的一件事是为枚举提供助记符而不是数值。
  • 是的,但是如果您尝试使用 json.dumps(my_object) 序列化您的对象,它会返回所需的结果吗?如果您可以直接返回该结果,而不是通过 fastapi 的 jsonable_encoder

标签: python fastapi


【解决方案1】:

FastAPI 使用 ENCODERS_BY_TYPE(来自 pydantic.json)对一些基本数据类型进行编码。

ENCODERS_BY_TYPE: Dict[Type[Any], Callable[[Any], Any]] = {
    bytes: lambda o: o.decode(),
    Color: str,
    datetime.date: isoformat,
    datetime.datetime: isoformat,
    datetime.time: isoformat,
    datetime.timedelta: lambda td: td.total_seconds(),
    Decimal: decimal_encoder,
    Enum: lambda o: o.value,

所以我要覆盖默认的日期时间编码,就像

 ENCODERS_BY_TYPE[datetime] = lambda date_obj: date_obj.strftime("%Y-%m-%d %H:%M:%S")

【讨论】:

    【解决方案2】:

    现在我在json.dumps 中使用自定义编码器,如下所示:

    class TestEncoder(JSONEncoder):
        def default(self, obj):
            if isinstance(obj, EnumTestT):
                return TestEncoder.process_enum_test_t(obj)
    
    

    FastAPI 应用程序中的响应是:

    json_str = json.dumps(json_list, cls=TestEncoder).encode('utf-8')
    return Response(media_type="application/json", content=json_str)
    

    FastAPI 使用自定义编码器的问题在于,自定义编码器是在调用了所有标准编码器之后才调用的,并且无法覆盖该顺序。

    【讨论】:

      【解决方案3】:

      灵感来自 coder vx

      import datetime
      from fastapi.responses import JSONResponse 
      ...
      content = something to serialize 
      JSONResponse(jsonable_encoder(content,
          custom_encoder={datetime.datetime: lambda date_obj: 
          date_obj.strftime("%Y-%m-%d %H:%M:%S")})))
      

      【讨论】:

      • 您的答案可以通过额外的支持信息得到改进。请edit 添加更多详细信息,例如引用或文档,以便其他人可以确认您的答案是正确的。你可以找到更多关于如何写好答案的信息in the help center
      【解决方案4】:

      您可以通过返回 fastapi.responses.Response 来使用任何序列化程序,如下所示:

      from fastapi.responses import Response
      
      return Response(
          content=CustomJsonEncoder().to_string(result),
          media_type='application/json'
      )
      

      通过编写一个继承自 json.JSONEncoder 的类,您可以覆盖方法 def default(self, obj) 以更改特定数据类型的序列化。

      class CustomJsonEncoder(json.JSONEncoder):
      
          def default(self, obj):
              if isinstance(obj, specific_class_type):
                  return specific_serialization(obj)
      
          pass
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-25
        • 1970-01-01
        • 2011-05-01
        • 2016-09-16
        • 2013-02-25
        • 1970-01-01
        • 2014-07-21
        • 2014-07-02
        相关资源
        最近更新 更多