如何处理JavaScript与Python DRF请求体JSON字段命名差异?
解决DRF与AngularJS命名规范不匹配的问题
这个问题我做前后端分离项目时也碰到过,确实挺闹心——毕竟JS的驼峰命名和Python的下划线命名是各自生态的标准,直接对接肯定会出现字段不匹配的情况。给你几个实用的解决思路,按需选择就行:
方法一:在DRF序列化器中自定义转换逻辑(最灵活)
自己写一个序列化器基类,处理下划线和驼峰的双向转换,其他业务序列化器继承这个基类就行,不用重复造轮子:
from rest_framework import serializers class CamelCaseSerializer(serializers.ModelSerializer): def to_representation(self, instance): # 把Python下划线格式转成JS驼峰格式,返回给前端 ret = super().to_representation(instance) camel_case_data = {} for key, value in ret.items(): parts = key.split('_') # 比如 first_name → firstName camel_case_key = parts[0] + ''.join(part.capitalize() for part in parts[1:]) camel_case_data[camel_case_key] = value return camel_case_data def to_internal_value(self, data): # 把前端传的驼峰格式转成Python下划线格式,存入后端 snake_case_data = {} for key, value in data.items(): snake_case_key = '' for char in key: # 比如 firstName → first_name if char.isupper(): snake_case_key += '_' + char.lower() else: snake_case_key += char snake_case_data[snake_case_key] = value return super().to_internal_value(snake_case_data)
使用示例:你的用户序列化器直接继承这个基类
class UserSerializer(CamelCaseSerializer): class Meta: model = User fields = ('first_name', 'last_name')
这样前端传{"firstName": "Mangu Singh", "lastName": "Rajpurohit"}时,后端会自动转成first_name和last_name;返回数据时又会自动转回驼峰格式,完全不用改前后端业务代码。
方法二:用DRF第三方包快速解决(最省心)
有现成的第三方包djangorestframework-camel-case已经封装好了上述转换逻辑,安装配置后就能全局生效:
- 安装包
pip install djangorestframework-camel-case
- 在
settings.py中配置DRF的渲染器和解析器
REST_FRAMEWORK = { 'DEFAULT_RENDERER_CLASSES': ( 'djangorestframework_camel_case.render.CamelCaseJSONRenderer', # 保留你原本需要的其他渲染器,比如BrowsableAPIRenderer 'rest_framework.renderers.BrowsableAPIRenderer', ), 'DEFAULT_PARSER_CLASSES': ( 'djangorestframework_camel_case.parser.CamelCaseJSONParser', 'rest_framework.parsers.FormParser', 'rest_framework.parsers.MultiPartParser', ), }
配置完成后,所有接口都会自动处理命名转换,适合中大型项目,不用手动写基类。
方法三:在AngularJS端通过拦截器处理
如果后端不想做改动,也可以在前端写一个HTTP拦截器,自动转换请求和响应的字段名:
// 自定义拦截器:处理命名格式转换 app.factory('namingConverterInterceptor', function() { // 驼峰转下划线 function camelToSnake(str) { return str.replace(/[A-Z]/g, letter => `_${letter.toLowerCase()}`); } // 下划线转驼峰 function snakeToCamel(str) { return str.replace(/_[a-z]/g, match => match[1].toUpperCase()); } // 递归转换对象/数组的所有键 function convertKeys(obj, converter) { if (typeof obj !== 'object' || obj === null) return obj; if (Array.isArray(obj)) return obj.map(item => convertKeys(item, converter)); return Object.keys(obj).reduce((acc, key) => { acc[converter(key)] = convertKeys(obj[key], converter); return acc; }, {}); } return { // 请求时:驼峰转下划线 request: function(config) { if (config.data) config.data = convertKeys(config.data, camelToSnake); return config; }, // 响应时:下划线转驼峰 response: function(response) { if (response.data) response.data = convertKeys(response.data, snakeToCamel); return response; } }; }); // 注册拦截器 app.config(function($httpProvider) { $httpProvider.interceptors.push('namingConverterInterceptor'); });
这个方法适合前端团队更愿意主导格式转换的场景,后端完全不用做任何修改。
总结
个人最推荐方法二(第三方包),省心又高效;如果需要自定义一些特殊字段的转换逻辑,方法一更灵活;前端主导的话就用方法三。
内容的提问来源于stack exchange,提问作者Mangu Singh Rajpurohit
相关产品推荐
相关产品推荐

