如何在DRF中用orjson/ujson替换默认序列化器?附代码示例
如何在Django REST Framework中用orjson/ujson替代默认JSON序列化
当然可以替换,核心思路是自定义DRF的JSON渲染器,用orjson/ujson替代Python标准库的json模块完成最终的JSON序列化,你的视图集和序列化器不需要大规模修改,只需按以下步骤操作:
1. 安装依赖
先安装你选择的高性能JSON库:
# 安装orjson pip install orjson # 或者安装ujson pip install ujson
2. 自定义JSON渲染器
在项目中创建renderers.py文件,实现基于orjson或ujson的渲染器:
基于orjson的实现
from rest_framework.renderers import BaseRenderer import orjson from decimal import Decimal from datetime import datetime class OrJSONRenderer(BaseRenderer): media_type = 'application/json' format = 'json' def render(self, data, media_type=None, renderer_context=None): if data is None: return b'' # 保留DRF原生错误响应格式 if isinstance(data, dict) and 'detail' in data: pass # 处理Decimal、datetime等orjson默认不支持的类型 def default(obj): if isinstance(obj, Decimal): return float(obj) # 也可转成字符串,根据业务需求选择 if isinstance(obj, datetime): return obj.isoformat() raise TypeError(f"无法序列化类型: {type(obj)}") # 配置orjson选项,如缩进、支持numpy类型等 options = orjson.OPT_INDENT_2 | orjson.OPT_SERIALIZE_NUMPY return orjson.dumps(data, default=default, option=options)
基于ujson的实现
from rest_framework.renderers import BaseRenderer import ujson from decimal import Decimal from datetime import datetime class UJSONRenderer(BaseRenderer): media_type = 'application/json' format = 'json' def render(self, data, media_type=None, renderer_context=None): if data is None: return b'' # 递归处理特殊类型,适配ujson的序列化规则 def handle_special_types(obj): if isinstance(obj, dict): return {k: handle_special_types(v) for k, v in obj.items()} elif isinstance(obj, list): return [handle_special_types(item) for item in obj] elif isinstance(obj, Decimal): return float(obj) elif isinstance(obj, datetime): return obj.isoformat() else: return obj processed_data = handle_special_types(data) return ujson.dumps(processed_data).encode('utf-8')
3. 配置DRF使用自定义渲染器
在项目的settings.py中,修改DRF默认渲染器配置,替换原生的JSONRenderer:
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': [ 'your_app_name.renderers.OrJSONRenderer', # 替换为你实际的文件路径 # 保留可浏览API渲染器,方便开发调试 'rest_framework.renderers.BrowsableAPIRenderer', ], }
针对你的代码的额外优化建议
你提供的ProfileViewSet和ProfileSerializer无需修改,但可以优化数据库查询逻辑进一步提升响应速度:
- 原
get_images方法中直接查询UserPhoto会产生额外的数据库请求,可在视图集的get_queryset中提前预加载关联数据:
def get_queryset(self): # ... 原有逻辑 ... users_not_taken_action = Profile.objects.exclude(user__in=users_taken_action) \ .exclude(user__in=blocked_users).exclude(user__id=current_id) \ .prefetch_related('user__userphoto_set') # 提前加载用户的照片数据 return users_not_taken_action
然后修改序列化器中的get_images方法:
def get_images(self, obj): return PhotoSerializer(obj.user.userphoto_set.all(), many=True).data
这样既用上了高性能JSON序列化库,又减少了数据库查询次数,能显著提升接口响应效率。
内容的提问来源于stack exchange,提问作者rafaelHTML
相关产品推荐
相关产品推荐

