Skip to content

Export OpenAPI Schema in Chinese

Me

In this code, if the --api parameter is passed via the command line, what should its format be?

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
In this code, the `--api` parameter is used to specify an API instance module. According to the comments and docstring in the code, the format of the `--api` parameter should be a **module path** — specifically, a Python module path that can be resolved by Django's `import_string` function.

### Format
```shell script
--api <module_path>

Example

Assume your project structure is as follows:

project/
    urls.py
    api.py

If the NinjaAPI instance is defined in the project/api.py file and the instance is named api, you can pass the parameter like this: ```shell script python manage.py export_openapi_schema --api project.api.api

### Notes
1. `<module_path>` is a Python module path pointing to the module that contains the `NinjaAPI` instance.
2. The last part of the path is the variable name of the `NinjaAPI` instance in the module (for example, `api`).
3. If the `--api` parameter is not provided, the code attempts to fetch the `NinjaAPI` instance dynamically via `resolve("/coast/api/")`. If that fails, it raises an error prompting the user to specify it explicitly via the `--api` parameter.

### Caveats
- Make sure the provided module path is valid and that a `NinjaAPI` instance actually exists in the module. Otherwise, the code will raise a `CommandError` indicating that the module or attribute was not found.
- If you are unsure of the path to the `NinjaAPI` instance, refer to your project's `urls.py` or other related files to find where the `NinjaAPI` is instantiated.

Hope this helps you understand how to use the `--api` parameter!

## Me
How should I fill in the `api` parameter so that it is equivalent to `resolve("/coast/api/")`?


## AI Assistant
To make the `--api` parameter equivalent to the behavior of `resolve("/coast/api/")`, the following points need to be clarified:

1. **What `resolve("/coast/api/")` does**  
   According to the logic in the code:
```python
resolve("/coast/api/").func.keywords["api"]

The purpose of this line is to use Django's URL routing resolution to find the view function associated with the path /coast/api/ and extract the value named "api" from that function's keyword arguments. This value should be a NinjaAPI instance.

  1. Equivalence condition
    If you want to achieve the same effect via the --api parameter, you need to know which module the NinjaAPI instance corresponding to /coast/api/ is defined in, and pass its path to the --api parameter.

How to determine the equivalent --api parameter?

Method 1: Inspect the project URL configuration

Typically, the URL routes for a Django project are configured in the urls.py file. Open the project's urls.py and find the part related to /coast/api/. For example:

# project/urls.py
from django.urls import path
from .api import api  # Assume the NinjaAPI instance is named `api`

urlpatterns = [
    path("coast/api/", api.urls),  # Mount `api`'s routes under `/coast/api/`
]

In this example: - api is a NinjaAPI instance. - It is defined in the module project.api (assuming the project root directory is project).

Therefore, the equivalent --api parameter should be: ```shell script --api project.api.api

---

#### Method 2: Confirm by dynamic debugging
If you cannot directly find the location of the `NinjaAPI` instance from the `urls.py` file, you can confirm it via debugging. The code already contains `pdb.set_trace()`, which allows you to pause the program at runtime and inspect the result of `resolve("/coast/api/")`:

1. Run the command without the `--api` parameter:
```shell script
python manage.py export_openapi_schema

  1. The program will pause at pdb.set_trace(). At this point, enter the following command to inspect the result of resolve("/coast/api/"):

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

  2. Confirm the returned object and its module path. For example, if the returned object is <NinjaAPI: api> and it is defined in the module project.api, then the equivalent --api parameter is: ```shell script --api project.api.api

    Export the OpenAPI schema in Chinese in django-ninja
    ---
    
    ## Me
    In `json.dumps`, what is the purpose of the `ensure_ascii` parameter?
    
    ## AI Assistant
    In Python's `json.dumps` method, the `ensure_ascii` parameter controls whether the generated JSON string contains only ASCII characters.
    
    ### Default behavior
    - **Default value**: `ensure_ascii=True`
    - When set to `True`, non-ASCII characters (such as Chinese, Japanese, special symbols, etc.) will be escaped into `\uXXXX` format Unicode sequences.  
      For example:
    ```python
    import json
    
      data = {"name": "张三", "age": 30}
      result = json.dumps(data, ensure_ascii=True)
      print(result)
    

Output:

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


Set to False

  • When set to False, non-ASCII characters are output directly as their original characters without being escaped. For example:
    import json
    
      data = {"name": "张三", "age": 30}
      result = json.dumps(data, ensure_ascii=False)
      print(result)
    

Output:

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


Use cases

  1. ensure_ascii=True:

    • Use this option when the generated JSON data needs to be compatible with systems or protocols that only support ASCII characters (for example, some older HTTP clients).
    • Example: storing data in a database field that only supports ASCII.
  2. ensure_ascii=False:

    • When you need to generate more readable JSON data (especially when it contains multilingual text), it is recommended to set this parameter to False.
    • Example: returning JSON data directly to the frontend, keeping non-ASCII characters readable.

Summary

  • ensure_ascii=True: Non-ASCII characters are escaped into \uXXXX format.
  • ensure_ascii=False: Non-ASCII characters are output directly as their original characters.

Specifically in django-ninja, if you need to export Chinese characters, you can adjust the parameters of the json.dumps function in the export_openapi_schema.py file.


本文总阅读量次