Skip to content

Commit

Permalink
Add Doc, Guide and Test. Change SCHEMA_GENERATION_CLASS to SCHEMA_GEN…
Browse files Browse the repository at this point in the history
…ERATOR_CLASS
  • Loading branch information
Eittipat committed Jan 14, 2024
1 parent 33610d7 commit 8e065cc
Show file tree
Hide file tree
Showing 7 changed files with 135 additions and 5 deletions.
27 changes: 27 additions & 0 deletions docs/docs/guides/custom-schema-generator.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# Custom Schema Generator

**Django Ninja** allows you to custom schema generator by change `NINJA_SCHEMA_GENERATOR_CLASS` in your settings.py

Example Full Qualified Schema Name:

```python
from ninja.schema import NinjaGenerateJsonSchema
from pydantic.json_schema import CoreModeRef, DefsRef


class CustomNinjaGenerateJsonSchema(NinjaGenerateJsonSchema):

def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef:
module_qualname_occurrence_mode = super().get_defs_ref(core_mode_ref)
name_choices = self._prioritized_defsref_choices[module_qualname_occurrence_mode]
name_choices.pop(0)
name_choices.pop(0)
self._prioritized_defsref_choices[module_qualname_occurrence_mode] = name_choices
return module_qualname_occurrence_mode
```

In your `settings.py`:

```python
NINJA_SCHEMA_GENERATOR_CLASS = 'path.to.CustomNinjaGenerateJsonSchema'
```
1 change: 1 addition & 0 deletions docs/mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ nav:
- guides/urls.md
- guides/async-support.md
- guides/versioning.md
- guides/custom-schema-generator.md
- Reference:
- NinjaAPI class: reference/api.md
- reference/csrf.md
Expand Down
7 changes: 5 additions & 2 deletions ninja/conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ class Settings(BaseModel):
The default page size. Defaults to `100`.
NINJA_PAGINATION_MAX_LIMIT (int):
The maximum number of results per page. Defaults to `inf`.
NINJA_SCHEMA_GENERATOR_CLASS (str):
The schema generation class to use. Defaults to
`ninja.schema.NinjaGenerateJsonSchema`.
"""

PAGINATION_CLASS: str = Field(
Expand All @@ -25,8 +28,8 @@ class Settings(BaseModel):
PAGINATION_PER_PAGE: int = Field(100, alias="NINJA_PAGINATION_PER_PAGE")
PAGINATION_MAX_LIMIT: int = Field(inf, alias="NINJA_PAGINATION_MAX_LIMIT")

SCHEMA_GENERATION_CLASS: str = Field(
"ninja.schema.NinjaGenerateJsonSchema", alias="NINJA_SCHEMA_GENERATION_CLASS"
SCHEMA_GENERATOR_CLASS: str = Field(
"ninja.schema.NinjaGenerateJsonSchema", alias="NINJA_SCHEMA_GENERATOR_CLASS"
)

class Config:
Expand Down
4 changes: 2 additions & 2 deletions ninja/openapi/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ def _extract_parameters(self, model: TModel) -> List[DictStrAny]:

schema = model.model_json_schema(
ref_template=REF_TEMPLATE,
schema_generator=import_string(settings.SCHEMA_GENERATION_CLASS),
schema_generator=import_string(settings.SCHEMA_GENERATOR_CLASS),
)

required = set(schema.get("required", []))
Expand Down Expand Up @@ -216,7 +216,7 @@ def _create_schema_from_model(
schema = model.model_json_schema(
ref_template=REF_TEMPLATE,
by_alias=by_alias,
schema_generator=import_string(settings.SCHEMA_GENERATION_CLASS),
schema_generator=import_string(settings.SCHEMA_GENERATOR_CLASS),
).copy()

# move Schemas from definitions
Expand Down
2 changes: 1 addition & 1 deletion ninja/schema.py
Original file line number Diff line number Diff line change
Expand Up @@ -233,7 +233,7 @@ def dict(self, *a: Any, **kw: Any) -> DictStrAny:
@classmethod
def json_schema(cls) -> DictStrAny:
return cls.model_json_schema(
schema_generator=import_string(settings.SCHEMA_GENERATION_CLASS)
schema_generator=import_string(settings.SCHEMA_GENERATOR_CLASS)
)

@classmethod
Expand Down
1 change: 1 addition & 0 deletions tests/test_conf.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@
def test_default_configuration():
assert settings.PAGINATION_CLASS == "ninja.pagination.LimitOffsetPagination"
assert settings.PAGINATION_PER_PAGE == 100
assert settings.SCHEMA_GENERATOR_CLASS == "ninja.schema.NinjaGenerateJsonSchema"
98 changes: 98 additions & 0 deletions tests/test_custom_schema_generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
import pytest
from pydantic.json_schema import CoreModeRef, DefsRef

from ninja import NinjaAPI
from ninja.conf import settings
from ninja.schema import Field, NinjaGenerateJsonSchema, Schema


class FullSchemaNameGenerator(NinjaGenerateJsonSchema):
def get_defs_ref(self, core_mode_ref: CoreModeRef) -> DefsRef:
temp = super().get_defs_ref(core_mode_ref)
choices = self._prioritized_defsref_choices[temp]
choices.pop(0)
choices.pop(0)
self._prioritized_defsref_choices[temp] = choices
return temp


class Payload(Schema):
i: int
f: float


def to_camel(string: str) -> str:
return "".join(word.capitalize() for word in string.split("_"))


class Response(Schema):
i: int
f: float = Field(..., title="f title", description="f desc")

class Config(Schema.Config):
alias_generator = to_camel
populate_by_name = True


@pytest.fixture(scope="function")
def schema():
# setup up
settings.SCHEMA_GENERATOR_CLASS = (
"tests.test_custom_schema_generator.FullSchemaNameGenerator"
)
api = NinjaAPI()

@api.post("/test", response=Response)
def method(request, data: Payload):
return data.dict()

yield api.get_openapi_schema()
# reset
settings.SCHEMA_GENERATOR_CLASS = "ninja.schema.NinjaGenerateJsonSchema"


def test_full_name_schema(schema):
method = schema["paths"]["/api/test"]["post"]

assert method["requestBody"] == {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/test_custom_schema_generator__Payload"
}
}
},
"required": True,
}
assert method["responses"] == {
200: {
"content": {
"application/json": {
"schema": {
"$ref": "#/components/schemas/test_custom_schema_generator__Response"
}
}
},
"description": "OK",
}
}
assert schema.schemas == {
"test_custom_schema_generator__Response": {
"title": "Response",
"type": "object",
"properties": {
"i": {"title": "I", "type": "integer"},
"f": {"description": "f desc", "title": "f title", "type": "number"},
},
"required": ["i", "f"],
},
"test_custom_schema_generator__Payload": {
"title": "Payload",
"type": "object",
"properties": {
"i": {"title": "I", "type": "integer"},
"f": {"title": "F", "type": "number"},
},
"required": ["i", "f"],
},
}

0 comments on commit 8e065cc

Please sign in to comment.