網站首頁 編程語言 正文
1、問題溯源
重點就是一個Flask.make_response,這里會做請求的響應的處理。
里面行代碼:
elif isinstance(rv, dict):
rv = jsonify(rv)
rv是我需要返回的響應:
{
'msg': [
{'roleName': 'guest', 'access_list':[<accessName root>]},
{'roleName': 'admin', 'access_list': [...]}
],
'error_no': 0
}
rv是一個字典,但是msg的里面有部分東西無法序列化,jsonify里面返回如下。
return current_app.response_class(
f"{dumps(data, indent=indent, separators=separators)}\n",
mimetype=current_app.config["JSONIFY_MIMETYPE"],
)
里面的data就是上面交道的類似json的數據(不是json,實際是對象)。
接下來:調用了flask下的自帶的一個json庫。
代碼片段: M-1
_dump_arg_defaults(kwargs, app=app)
return _json.dumps(obj, **kwargs)
代碼片段: M -2
if cls is None:
cls = JSONEncoder
return cls(
skipkeys=skipkeys, ensure_ascii=ensure_ascii,
check_circular=check_circular, allow_nan=allow_nan, indent=indent,
separators=separators, default=default, sort_keys=sort_keys,
**kw).encode(obj)
這里的obj的:
{'msg': [{...}, {...}], 'error_no': 0}
就是我們之前講到的東西。
代碼片段: M-4,這個是內置的json庫的default方法。內置的沒有實現序列化,所以需要自己在某個步驟接入到這個序列化的過程。
def default(self, o):
"""Implement this method in a subclass such that it returns
a serializable object for ``o``, or calls the base implementation
(to raise a ``TypeError``).
For example, to support arbitrary iterators, you could
implement default like this::
def default(self, o):
try:
iterable = iter(o)
except TypeError:
pass
else:
return list(iterable)
# Let the base class default method raise the TypeError
return JSONEncoder.default(self, o)
"""
raise TypeError(f'Object of type {o.__class__.__name__} '
f'is not JSON serializable')
o在這里就是AccessOrm是實例對象,所以他報錯說這個:
Object of type AccessOrm is not JSON serializable
歸因:就是flask沒有自帶實現對類的序列化
解決: 就是通過flask的機制,綁定一個序列化類。
2、flask序列化
flask代碼里面寫了:
class JSONEncoder(_json.JSONEncoder):
"""The default JSON encoder. Handles extra types compared to the
built-in :class:`json.JSONEncoder`.
- :class:`datetime.datetime` and :class:`datetime.date` are
serialized to :rfc:`822` strings. This is the same as the HTTP
date format.
- :class:`uuid.UUID` is serialized to a string.
- :class:`dataclasses.dataclass` is passed to
:func:`dataclasses.asdict`.
- :class:`~markupsafe.Markup` (or any object with a ``__html__``
method) will call the ``__html__`` method to get a string.
Assign a subclass of this to :attr:`flask.Flask.json_encoder` or
:attr:`flask.Blueprint.json_encoder` to override the default.
"""
在片段代碼M-1中:
_dump_arg_defaults(kwargs, app=app)
函數內容如下:
def _dump_arg_defaults(
kwargs: t.Dict[str, t.Any], app: t.Optional["Flask"] = None
) -> None:
"""Inject default arguments for dump functions."""
if app is None:
app = current_app
if app:
cls = app.json_encoder #app的json_encoder
bp = app.blueprints.get(request.blueprint) if request else None # type: ignore
if bp is not None and bp.json_encoder is not None:
cls = bp.json_encoder #這里設置藍圖的json_encoder,藍圖的優先級高于app.json_encoder
# Only set a custom encoder if it has custom behavior. This is
# faster on PyPy.
if cls is not _json.JSONEncoder:
kwargs.setdefault("cls", cls)
kwargs.setdefault("cls", cls)
kwargs.setdefault("ensure_ascii", app.config["JSON_AS_ASCII"])
kwargs.setdefault("sort_keys", app.config["JSON_SORT_KEYS"])
else:
kwargs.setdefault("sort_keys", True)
kwargs.setdefault("cls", JSONEncoder)
3、解決方法
使用自帶的序列化類
在入口函數setup.py中寫入
from flask import Flask
from flask.json import JSONEncoder
from config import Config,LogConfig
from db import init_db
from scripts import user_cli
from flask_bcrypt import Bcrypt
from utils import RedisPool
class ExtendJSONEncoder(JSONEncoder):
def default(self, o):
if getattr(o,'toJson'):
return o.toJson(o)
else:
return super().default(o)
flask_bcrypt = Bcrypt()
def create_app():
Flask.json_encoder = ExtendJSONEncoder
#之前在with app.app_context()
#或者在app實例化之后,修改app的JSONEncoder 都沒成功,這里簡單粗暴一點,直接修改Flask的。
app = Flask(__name__)
app.config.from_object(Config)
LogConfig.openLog()
from utils import initException,initBeforeRequestHandle
with app.app_context():
init_db(app)
RedisPool(app)
initException(app)
initBeforeRequestHandle(app)
flask_bcrypt.init_app(app)
app.cli.add_command(user_cli)
import controller
for bp in controller.__all__:
app.register_blueprint(controller.__dict__[bp])
return app
這時候,我的orm類需要一個toJson方法。
class AccessOrm(Base):
__tablename__ = 'access'
id = Column(Integer, primary_key=True)
accessName = Column(String(255), nullable=True)
def __repr__(self) -> str:
return "<accessName {}>".format(
self.accessName,
)
def toJson(self,o):
return {
'accessName': o.accessName,
}
原文鏈接:https://blog.csdn.net/baidu_36831253/article/details/127652192
相關推薦
- 2022-02-03 checkbox修改默認樣式
- 2023-01-18 React報錯Element?type?is?invalid解決案例_React
- 2022-11-26 React從插槽、路由、redux的詳細過程_React
- 2022-09-22 求解器選擇與收斂性問題(OR-Tools)
- 2023-06-03 一文帶你吃透Python中的os和sys模塊_python
- 2022-09-02 pytest使用@pytest.mark.parametrize()實現參數化的示例代碼_pytho
- 2022-10-06 C++?pimpl機制詳細講解_C 語言
- 2022-08-04 python實現凱撒密碼加密解密的示例代碼_python
- 最近更新
-
- window11 系統安裝 yarn
- 超詳細win安裝深度學習環境2025年最新版(
- Linux 中運行的top命令 怎么退出?
- MySQL 中decimal 的用法? 存儲小
- get 、set 、toString 方法的使
- @Resource和 @Autowired注解
- Java基礎操作-- 運算符,流程控制 Flo
- 1. Int 和Integer 的區別,Jav
- spring @retryable不生效的一種
- Spring Security之認證信息的處理
- Spring Security之認證過濾器
- Spring Security概述快速入門
- Spring Security之配置體系
- 【SpringBoot】SpringCache
- Spring Security之基于方法配置權
- redisson分布式鎖中waittime的設
- maven:解決release錯誤:Artif
- restTemplate使用總結
- Spring Security之安全異常處理
- MybatisPlus優雅實現加密?
- Spring ioc容器與Bean的生命周期。
- 【探索SpringCloud】服務發現-Nac
- Spring Security之基于HttpR
- Redis 底層數據結構-簡單動態字符串(SD
- arthas操作spring被代理目標對象命令
- Spring中的單例模式應用詳解
- 聊聊消息隊列,發送消息的4種方式
- bootspring第三方資源配置管理
- GIT同步修改后的遠程分支