Skip to content

Commit 12af6ff

Browse files
authored
Merge pull request #217 from eadwinCode/model_config_extra_options
feat: Model config extra options for Model Controller
2 parents 6327357 + 63517ed commit 12af6ff

File tree

4 files changed

+46
-10
lines changed

4 files changed

+46
-10
lines changed

docs/api_controller/model_controller.md

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,14 @@ from .models import Event
4242
class EventModelController(ModelControllerBase):
4343
model_config = ModelConfig(
4444
model=Event,
45-
schema_config=ModelSchemaConfig(read_only_fields=["id", "category"]),
45+
schema_config=ModelSchemaConfig(
46+
read_only_fields=["id", "category"],
47+
# if you want to extra configuration to the generated schemas
48+
# extra_config_dict={
49+
# 'title': 'EventCustomTitle',
50+
# 'populate_by_name': True
51+
# }
52+
),
4653
)
4754

4855
api = NinjaExtraAPI()
@@ -79,6 +86,7 @@ The `ModelConfig` is a Pydantic schema designed for validating and configuring t
7986
- `depth`: The depth for nesting schema generation.
8087
- `read_only_fields`: A list of fields to be excluded when generating input schemas for create, update, and patch operations.
8188
- `write_only_fields`: A list of fields to be excluded when generating output schemas for find_one and list operations.
89+
- `extra_config_dict`: A dictionary of extra configuration to be added to the generated schemas. Options must be valid Pydantic configuration options.
8290
- **pagination**: A requisite for the model `list/GET` operation to prevent sending `100_000` items at once in a request. The pagination configuration mandates a `ModelPagination` Pydantic schema object for setup. Options encompass:
8391
- `klass`: The pagination class of type `PaginationBase`. The default is `PageNumberPaginationExtra`.
8492
- `paginator_kwargs`: A dictionary value for `PaginationBase` initialization. The default is None.
@@ -305,8 +313,10 @@ class EventModelController(ModelControllerBase):
305313
custom_handler=lambda self, data, **kw: self.handle_add_event_to_new_category(data, **kw)
306314
)
307315

308-
def handle_add_event_to_new_category(self, data: CreateCategorySchema, **kw: Any) -> Category:
309-
event = self.service.get_one(pk=kw['event_id'])
316+
def handle_add_event_to_new_category(
317+
self, data: CreateCategorySchema, event_id: int, **kw: Any
318+
) -> Category:
319+
event = self.service.get_one(pk=event_id)
310320
category = Category.objects.create(title=data.title)
311321
event.category = category
312322
event.save()
@@ -361,8 +371,10 @@ class EventModelController(ModelControllerBase):
361371
custom_handler=lambda self, data, **kw: self.handle_add_event_to_new_category(data, **kw)
362372
)
363373

364-
async def handle_add_event_to_new_category(self, data: CreateCategorySchema, **kw: Any) -> Category:
365-
event = await self.service.get_one_async(pk=kw['event_id'])
374+
async def handle_add_event_to_new_category(
375+
self, data: CreateCategorySchema, event_id: int, **kw: Any
376+
) -> Category:
377+
event = await self.service.get_one_async(pk=event_id)
366378
category = Category.objects.create(title=data.title)
367379
event.category = category
368380
event.save()

ninja_extra/controllers/model/schemas.py

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
import typing as t
22

3+
from django.core.exceptions import ImproperlyConfigured
34
from django.db.models import Model
45
from ninja.pagination import PaginationBase
56
from pydantic import BaseModel as PydanticModel
67
from pydantic import Field, field_validator
78

89
try:
10+
from ninja_schema import __version__ as ninja_schema_version
911
from ninja_schema.errors import ConfigError
1012
from ninja_schema.orm.factory import SchemaFactory
1113
from ninja_schema.orm.model_schema import (
@@ -14,15 +16,24 @@
1416
from ninja_schema.orm.model_schema import (
1517
ModelSchemaConfigAdapter,
1618
)
19+
20+
NINJA_SCHEMA_VERSION = tuple(map(int, ninja_schema_version.split(".")))
1721
except Exception: # pragma: no cover
1822
ConfigError = NinjaSchemaModelSchemaConfig = ModelSchemaConfigAdapter = (
1923
SchemaFactory
2024
) = None
25+
NINJA_SCHEMA_VERSION = (0, 0, 0)
2126

2227

2328
from ninja_extra.pagination import PageNumberPaginationExtra, PaginatedResponseSchema
2429

2530

31+
def _is_ninja_schema_version_supported() -> bool:
32+
if NINJA_SCHEMA_VERSION[1] >= 14 and NINJA_SCHEMA_VERSION[2] >= 1:
33+
return True
34+
raise ImproperlyConfigured("ninja-schema version 0.14.1 or higher is required")
35+
36+
2637
class ModelPagination(PydanticModel):
2738
"""
2839
Model Controller Pagination Configuration
@@ -54,9 +65,10 @@ class ModelSchemaConfig(PydanticModel):
5465
exclude: t.Set[str] = Field(set())
5566
optional: t.Optional[t.Union[str, t.Set[str]]] = Field(default=None)
5667
depth: int = 0
57-
#
68+
5869
read_only_fields: t.Optional[t.List[str]] = Field(default=None)
5970
write_only_fields: t.Optional[t.Union[t.List[str]]] = Field(default=None)
71+
extra_config_dict: t.Optional[t.Dict[str, t.Any]] = Field(default=None)
6072

6173

6274
class ModelConfig(PydanticModel):
@@ -146,6 +158,9 @@ def generate_all_schema(self) -> None:
146158
exclude_fields = set(self.schema_config.exclude)
147159
working_fields = working_fields - exclude_fields
148160

161+
if self.schema_config.extra_config_dict:
162+
_is_ninja_schema_version_supported()
163+
149164
if not self.create_schema and "create" in self.allowed_routes:
150165
create_schema_fields = self._get_create_schema_fields(
151166
working_fields, model_pk
@@ -156,6 +171,7 @@ def generate_all_schema(self) -> None:
156171
fields=list(create_schema_fields),
157172
skip_registry=True,
158173
depth=self.schema_config.depth,
174+
**(self.schema_config.extra_config_dict or {}),
159175
)
160176

161177
if not self.update_schema and "update" in self.allowed_routes:
@@ -166,7 +182,9 @@ def generate_all_schema(self) -> None:
166182
working_fields, model_pk
167183
)
168184
self.update_schema = SchemaFactory.create_schema(
169-
self.model, fields=list(create_schema_fields)
185+
self.model,
186+
fields=list(create_schema_fields),
187+
**(self.schema_config.extra_config_dict or {}),
170188
)
171189

172190
if not self.patch_schema and "patch" in self.allowed_routes:
@@ -180,6 +198,7 @@ def generate_all_schema(self) -> None:
180198
optional_fields=list(create_schema_fields),
181199
skip_registry=True,
182200
depth=self.schema_config.depth,
201+
**(self.schema_config.extra_config_dict or {}),
183202
)
184203

185204
if not self.retrieve_schema:
@@ -192,6 +211,7 @@ def generate_all_schema(self) -> None:
192211
fields=list(retrieve_schema_fields),
193212
skip_registry=True,
194213
depth=self.schema_config.depth,
214+
**(self.schema_config.extra_config_dict or {}),
195215
)
196216

197217
def _get_create_schema_fields(self, working_fields: set, model_pk: str) -> set:

requirements-tests.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
django-stubs
22
mypy == 1.13.0
3-
ninja-schema>=0.14.0
3+
ninja-schema>=0.14.1
44
pytest
55
pytest-asyncio==0.24.0
66
pytest-cov

tests/test_model_controller/test_model_controller_configurations.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ def test_default_model_config():
4242
"depth": 0,
4343
"read_only_fields": None,
4444
"write_only_fields": None,
45+
"extra_config_dict": None,
4546
}
4647
assert model_config.create_route_info == {}
4748
assert model_config.find_one_route_info == {}
@@ -55,7 +56,10 @@ def test_include_gen_schema():
5556
model_config = ModelConfig(
5657
model=Event,
5758
allowed_routes=["list", "find_one"],
58-
schema_config=ModelSchemaConfig(include=["title", "start_date", "end_date"]),
59+
schema_config=ModelSchemaConfig(
60+
include=["title", "start_date", "end_date"],
61+
extra_config_dict={"title": "EventCustomTitle"},
62+
),
5963
)
6064
assert model_config.create_schema is None
6165
assert model_config.patch_schema is None
@@ -83,7 +87,7 @@ def test_include_gen_schema():
8387
},
8488
},
8589
"required": ["id", "title", "start_date", "end_date"],
86-
"title": "EventSchema",
90+
"title": "EventCustomTitle",
8791
"type": "object",
8892
}
8993

0 commit comments

Comments
 (0)