You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.26 14:43:13