Python Django Ninja 框架 snake-case蛇形 转换 camel-case 驼峰

方案一:定义 Schema 进行转换

在 Django Ninja 中,可以实现自动转换,不需要手动重命名每个字段。以下是具体实现方式:

自动转换方案(基于您现有代码)

python
复制代码
from ninja import Schema from pydantic import Field from pydantic.alias_generators import to_camel from typing import Optional class CamelModel(Schema): class Config: alias_generator = to_camel # 自动snake_case -> camelCase populate_by_name = True # 允许通过别名访问 class UserLoginResponse(CamelModel): # 继承自CamelModel # 保持原有字段名(snake_case),会自动转为camelCase user_account: str user_name: str user_id: int avatar_url: Optional[str] = None # ...其他字段保持原样...

关键点说明

  1. alias_generator = to_camel:自动将 snake_case 转为 camelCase
  2. populate_by_name = True:允许通过原始字段名访问
  3. 无需修改现有代码:
  • 服务层继续返回 user_account 等 snake_case 字段
  • 前端将收到 userAccount 等 camelCase 字段

效果验证

python
复制代码
# 测试输出 response = UserLoginResponse( user_account="test", user_name="Test User", user_id=1 ) print(response.json()) # 输出: {"userAccount":"test","userName":"Test User","userId":1}

这样既保持了后端代码的 Python 风格,又满足了前端 JavaScript 的命名习惯

保险起见的写法

1. 自动转换已足够的情况

python
复制代码
class UserLoginResponse(CamelModel): user_account: str # 会自动转为 userAccount # ...其他字段...
  • 足够:如果所有字段都遵循 snake_case 命名规范
  • 自动转换:alias_generator = to_camel 会处理大多数情况

2. 需要显式 Field 的情况

python
复制代码
class UserLoginResponse(CamelModel): user_account: str = Field(alias="userAccount") # 显式指定 # ...其他字段...
  • 特殊字段:当字段名不符合常规转换规则时
  • 文档清晰:让 API 文档明确显示前端应该使用的字段名
  • 前后端约定:确保即使未来修改转换逻辑,该字段名保持不变

!!! 但是这种定义 不能对 request 起到效果

因为,在 ninja 项目源码中的schema.py 下的 DjangoGetter class中的 def __getattr__(self, key: str) -> Any 函数,你会发现,框架,是先对request 中的 keys 和 schemas 的 keys 进行比对,保证数据符合要求再进行,对应的to_snake的转换,而不是先转换,request key 的格式,所以就会发生报错,

解决方式有用显示 Field ,alias 去处理如上方写法,定义每一个 字段,的 camel case ,这样 函数 会优先使用 alias 的字段,对比就不会出错

python
复制代码
class UserLoginRequest(RequestBase): user_account: str = Field(..., alias="userAccount") user_password: str = Field(..., alias="userPassword")

方案二,写个中间件,对所有请求进行字体转换

1. 这种也是解决,上面,省去对请求,每个字段进行表明写法的方法,创建中间件文件

推荐位置

plain
复制代码
your_project/ ├── middleware/ # 新建目录存放中间件 │ ├── __init__.py │ └── camel_case.py # 驼峰转蛇形中间件 ├── api.py # Django Ninja 的 api 实例 └── settings.py

middleware/camel_case.py 内容

python
复制代码
import json import re from django.utils.text import camel_case_to_spaces, slugify from django.http import HttpRequest def camel_to_snake(data): """递归将字典的键从 camelCase 转为 snake_case""" if isinstance(data, dict): return { # 转换逻辑:camelCase → snake_case slugify(camel_case_to_spaces(key)).replace("-", "_"): camel_to_snake(value) for key, value in data.items() } elif isinstance(data, list): return [camel_to_snake(item) for item in data] return data class CamelCaseMiddleware: def __init__(self, get_response): self.get_response = get_response def __call__(self, request: HttpRequest): # 只处理 JSON 请求(避免影响表单/文件上传等) if request.content_type == "application/json" and request.body: try: data = json.loads(request.body) # 修改请求体数据 request._body = json.dumps(camel_to_snake(data)).encode("utf-8") except json.JSONDecodeError: pass return self.get_response(request)

2. 注册中间件到 Django Ninja

api.py 中注册

python
复制代码
from ninja import NinjaAPI from .middleware.camel_case import CamelCaseMiddleware api = NinjaAPI() api.add_middleware(CamelCaseMiddleware) # 关键!添加中间件

3. 确保中间件能被导入

middleware/__init__.py 中暴露中间件

python
复制代码
from .camel_case import CamelCaseMiddleware __all__ = ["CamelCaseMiddleware"]

4. (可选)添加到 Django 全局中间件

如果希望中间件 对所有请求(包括非 API 请求)生效,可以在 settings.py 中添加:

python
复制代码
# settings.py MIDDLEWARE = [ ..., 'your_project.middleware.CamelCaseMiddleware', # 全局中间件 ]

不建议这样做,因为:

  1. 可能影响 Django Admin、静态文件等非 API 请求。
  2. Django Ninja 的 api.add_middleware() 是更精准的注册方式。

5. 测试中间件

发送请求

bash
复制代码
curl -X POST http://localhost:8000/api/user \ -H "Content-Type: application/json" \ -d '{"userName":"John", "userAge":25}'

后端接收的数据

python
复制代码
# 自动转换为: {"user_name": "John", "user_age": 25}

关键注意事项

  1. 中间件顺序
    Django Ninja 的中间件按注册顺序执行,确保转换中间件在认证中间件之前。
  2. 性能影响
    对每个 JSON 请求会进行递归转换,高频 API 可能需要优化。
  3. 异常处理
    中间件中捕获了 JSONDecodeError,避免非法 JSON 导致崩溃。
  4. Content-Type 检查
    仅处理 application/json 请求,避免影响文件上传等场景。

替代方案对比

方案优点缺点
中间件全局生效,无需改 Schema需要处理递归转换逻辑
Pydantic 别名声明式配置,代码更干净每个 Schema 需单独设置
手动转换灵活控制代码冗余,维护成本高

推荐优先使用 中间件Pydantic 别名,根据项目规模选择。

0个评论
点击登录,快来和大家讨论吧~
表情
图片
暂无评论
下载 APP