跳转至

django-ninja中导出 openapi schema为中文

这段代码中,如果通过命令行传递了 --api参数,它的格式应该是什么样的

import pdb
import json
from pathlib import Path
from typing import Any, Optional
from django.core.management.base import BaseCommand, CommandError, CommandParser
from django.urls.base import resolve
from django.utils.module_loading import import_string
from ninja.main import NinjaAPI
from ninja.management.utils import command_docstring
from ninja.responses import NinjaJSONEncoder

class Command(BaseCommand):
    """
    Example:
        ```terminal
        python manage.py export_openapi_schema
        ```
        ```terminal
        python manage.py export_openapi_schema --api project.urls.api
        ```
    """
    help = "Exports Open API schema"
    def _get_api_instance(self, api_path: Optional[str] = None) -> NinjaAPI:
        if not api_path:
            try:
                pdb.set_trace()
                return resolve("/coast/api/").func.keywords["api"]  # type: ignore
            except AttributeError:
                raise CommandError(
                    "No NinjaAPI instance found; please specify one with --api"
                ) from None
        try:
            api = import_string(api_path)
        except ImportError:
            raise CommandError(
                f"Module or attribute for {api_path} not found!"
            ) from None
        if not isinstance(api, NinjaAPI):
            raise CommandError(f"{api_path} is not instance of NinjaAPI!")
        return api
    def add_arguments(self, parser: CommandParser) -> None:
        parser.add_argument(
            "--api",
            dest="api",
            default=None,
            type=str,
            help="Specify api instance module",
        )
        parser.add_argument(
            "--output",
            dest="output",
            default=None,
            type=str,
            help="Output schema to a file (outputs to stdout if omitted).",
        )
        parser.add_argument(
            "--indent", dest="indent", default=None, type=int, help="JSON indent"
        )
        parser.add_argument(
            "--sorted",
            dest="sort_keys",
            default=False,
            action="store_true",
            help="Sort Json keys",
        )
    def handle(self, *args: Any, **options: Any) -> None:
        api = self._get_api_instance(options["api"])
        schema = api.get_openapi_schema()
        result = json.dumps(
            schema,
            cls=NinjaJSONEncoder,
            indent=options["indent"],
            sort_keys=options["sort_keys"],
        )
        if options["output"]:
            with Path(options["output"]).open("wb") as f:
                f.write(result.encode())
        else:
            self.stdout.write(result)

__doc__ = command_docstring(Command)
`


## AI Assistant
在这段代码中,`--api` 参数用于指定一个 API 实例模块。根据代码中的注释和文档字符串,`--api` 参数的格式应该是 **模块路径**,具体来说,是一个可以被 Django 的 `import_string` 函数解析的 Python 模块路径。

### 格式
```shell script
--api <module_path>

示例

假设你的项目结构如下:

project/
    urls.py
    api.py

如果 NinjaAPI 实例定义在 project/api.py 文件中,并且实例名为 api,那么你可以这样传递参数: ```shell script python manage.py export_openapi_schema --api project.api.api

### 说明
1. `<module_path>` 是一个 Python 模块路径,指向包含 `NinjaAPI` 实例的模块。
2. 路径的最后一部分是模块中 `NinjaAPI` 实例的变量名(例如 `api`)。
3. 如果未提供 `--api` 参数,代码会尝试通过 `resolve("/coast/api/")` 动态获取 `NinjaAPI` 实例。如果失败,则会抛出错误,提示用户必须通过 `--api` 参数显式指定。

### 注意事项
- 确保提供的模块路径是有效的,并且模块中确实存在一个 `NinjaAPI` 实例。否则,代码会抛出 `CommandError`,提示模块或属性未找到。
- 如果你不确定 `NinjaAPI` 实例的路径,可以参考项目的 `urls.py` 或其他相关文件,找到实例化 `NinjaAPI` 的位置。

希望这能帮助你理解如何使用 `--api` 参数!

## 我
怎样填写 api参数才能等价于`resolve("/coast/api/")`


## AI Assistant
要让 `--api` 参数等价于 `resolve("/coast/api/")` 的行为,需要明确以下几点:

1. **`resolve("/coast/api/")` 的作用**  
   根据代码中的逻辑:
```python
resolve("/coast/api/").func.keywords["api"]

这行代码的作用是通过 Django 的 URL 路由解析功能找到与路径 /coast/api/ 相关联的视图函数,并从该函数的关键字参数中提取名为 "api" 的值。这个值应该是一个 NinjaAPI 实例。

  1. 等价条件
    如果你希望通过 --api 参数实现同样的效果,则需要知道 /coast/api/ 对应的 NinjaAPI 实例在哪个模块中定义,并将其路径传递给 --api 参数。

如何确定等价的 --api 参数?

方法 1:检查项目的 URL 配置

通常,Django 项目的 URL 路由会在 urls.py 文件中配置。打开项目的 urls.py 文件,找到与 /coast/api/ 相关的部分。例如:

# project/urls.py
from django.urls import path
from .api import api  # 假设 NinjaAPI 实例名为 `api`

urlpatterns = [
    path("coast/api/", api.urls),  # 将 `api` 的路由挂载到 `/coast/api/`
]

在这个例子中: - api 是一个 NinjaAPI 实例。 - 它定义在模块 project.api 中(假设项目根目录为 project)。

因此,等价的 --api 参数应该是: ```shell script --api project.api.api

---

#### 方法 2:动态调试确认
如果无法直接从 `urls.py` 文件中找到 `NinjaAPI` 实例的位置,可以通过调试确认。代码中已经包含了 `pdb.set_trace()`,可以在运行时暂停程序并查看 `resolve("/coast/api/")` 的结果:

1. 运行命令时不带 `--api` 参数:
```shell script
python manage.py export_openapi_schema

  1. 程序会在 pdb.set_trace() 处暂停。此时,输入以下命令查看 resolve("/coast/api/") 的结果:

    resolve("/coast/api/").func.keywords["api"]
    

  2. 确认返回的对象及其模块路径。例如,如果返回的对象是 <NinjaAPI: api>,并且它定义在模块 project.api 中,则等价的 --api 参数为: ```shell script --api project.api.api

    django-ninja中导出 openapi schema为中文
    ---
    
    ## 我
    json.dumps中, ensure_ascii参数的作用
    
    ## AI Assistant
    在 Python 的 `json.dumps` 方法中,`ensure_ascii` 参数的作用是控制生成的 JSON 字符串是否仅包含 ASCII 字符。
    
    ### 默认行为
    - **默认值**: `ensure_ascii=True`
    - 当设置为 `True` 时,非 ASCII 字符(如中文、日文、特殊符号等)会被转义为 `\uXXXX` 格式的 Unicode 序列。  
      例如:
    ```python
    import json
    
      data = {"name": "张三", "age": 30}
      result = json.dumps(data, ensure_ascii=True)
      print(result)
    

输出:

{"name": "\u5f20\u4e09", "age": 30}


设置为 False

  • 当设置为 False 时,非 ASCII 字符会直接以原始字符形式输出,而不会被转义。 例如:
    import json
    
      data = {"name": "张三", "age": 30}
      result = json.dumps(data, ensure_ascii=False)
      print(result)
    

输出:

{"name": "张三", "age": 30}


使用场景

  1. ensure_ascii=True:

    • 如果需要生成的 JSON 数据兼容只支持 ASCII 字符的系统或协议(例如某些老旧的 HTTP 客户端),可以使用此选项。
    • 示例:将数据存储到仅支持 ASCII 的数据库字段中。
  2. ensure_ascii=False:

    • 如果需要生成更易读的 JSON 数据(尤其是包含多语言文本时),建议将此参数设置为 False
    • 示例:直接将 JSON 数据返回给前端,保持非 ASCII 字符的可读性。

总结

  • ensure_ascii=True:非 ASCII 字符会被转义为 \uXXXX 格式。
  • ensure_ascii=False:非 ASCII 字符会直接输出为原始字符。

具体在 django-ninja 中,如果需要导出的字符为中文,则可以调整 export_openapi_schema.py 文件中json.dumps函数的参数。


本文总阅读量