Model Configuration
The ModelConfig class in Ninja Extra provides extensive configuration options for Model Controllers. It allows you to customize schema generation, route behavior, and pagination settings.
Basic Configuration
Here's a comprehensive example of ModelConfig usage:
from ninja_extra import (
ModelConfig,
ModelControllerBase,
ModelSchemaConfig,
api_controller,
)
from .models import Event
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
schema_config=ModelSchemaConfig(
read_only_fields=["id", "created_at"],
write_only_fields=["password"],
include=["title", "start_date", "end_date", "category"],
exclude=set(), # Fields to exclude
depth=1, # Nesting depth for related fields
),
async_routes=False, # Enable/disable async routes
allowed_routes=["create", "find_one", "update", "patch", "delete", "list"],
)
Schema Configuration
The ModelSchemaConfig class controls how Pydantic schemas are generated from your Django models:
from ninja_extra import ModelConfig, ModelSchemaConfig
# Detailed schema configuration
schema_config = ModelSchemaConfig(
# Include specific fields (use "__all__" for all fields)
include=["title", "description", "start_date"],
# Exclude specific fields
exclude={"internal_notes", "secret_key"},
# Fields that should be read-only (excluded from create/update schemas)
read_only_fields=["id", "created_at", "updated_at"],
# Fields that should be write-only (excluded from retrieve schemas)
write_only_fields=["password"],
# Depth of relationship traversal
depth=1,
# Additional Pydantic config options
extra_config_dict={
"title": "EventSchema",
"description": "Schema for Event model",
"populate_by_name": True
}
)
model_config = ModelConfig(
model=Event,
schema_config=schema_config
)
Custom Schemas
You can provide your own Pydantic schemas instead of using auto-generated ones:
from datetime import date
from pydantic import BaseModel, Field
class EventCreateSchema(BaseModel):
title: str = Field(..., max_length=100)
start_date: date
end_date: date
category_id: int | None = None
class EventRetrieveSchema(BaseModel):
id: int
title: str
start_date: date
end_date: date
category_id: int | None
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
create_schema=EventCreateSchema,
retrieve_schema=EventRetrieveSchema,
update_schema=EventCreateSchema, # Reuse create schema for updates
)
Pagination Configuration
Model Controllers support customizable pagination for list endpoints:
from ninja.pagination import LimitOffsetPagination
from ninja_extra import (
ModelConfig,
ModelPagination
)
from ninja_extra.pagination import NinjaPaginationResponseSchema
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
# Configure pagination
pagination=ModelPagination(
klass=LimitOffsetPagination,
pagination_schema=NinjaPaginationResponseSchema,
paginator_kwargs={
"limit": 20,
"offset": 100
}
)
)
Pagination with Filtering
You can combine pagination with Django Ninja's FilterSchema to automatically add filtering capabilities to your Model Controller's list endpoint:
from typing import Optional
from ninja import FilterSchema
from ninja_extra import ModelConfig, ModelPagination
from ninja_extra.pagination import PageNumberPaginationExtra
# Define a FilterSchema for your model
class EventFilterSchema(FilterSchema):
title: Optional[str] = None
category: Optional[str] = None
start_date__gte: Optional[str] = None
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
pagination=ModelPagination(
klass=PageNumberPaginationExtra,
filter_schema=EventFilterSchema, # Add filtering support
paginator_kwargs={"page_size": 25}
)
)
This configuration automatically applies the FilterSchema to the list endpoint, allowing users to filter results:
GET /api/events/?title=Conference&category=Tech&page=1&page_size=25
Advanced Filtering with Custom Lookups
Use Django Ninja's FilterLookup annotation for more sophisticated filtering:
from typing import Annotated, Optional
from ninja import FilterSchema, FilterLookup
class AdvancedEventFilterSchema(FilterSchema):
# Case-insensitive search
title: Annotated[Optional[str], FilterLookup("title__icontains")] = None
# Date range filtering
start_date_after: Annotated[Optional[str], FilterLookup("start_date__gte")] = None
start_date_before: Annotated[Optional[str], FilterLookup("start_date__lte")] = None
# Related field filtering
category: Annotated[Optional[str], FilterLookup("category__name__iexact")] = None
# Multiple field search
search: Annotated[
Optional[str],
FilterLookup([
"title__icontains",
"description__icontains",
"location__icontains"
])
] = None
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
pagination=ModelPagination(
klass=PageNumberPaginationExtra,
filter_schema=AdvancedEventFilterSchema,
paginator_kwargs={"page_size": 50}
)
)
Learn More About FilterSchema
For comprehensive documentation on FilterSchema features, custom expressions, combining filters, and advanced filtering techniques, visit: https://django-ninja.dev/guides/input/filtering/
Route Configuration
You can customize individual route behavior using route info dictionaries. Each route type (create_route_info, list_route_info, find_one_route_info, update_route_info, patch_route_info, delete_route_info) accepts various configuration parameters.
Common Route Parameters
All route types support these common parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
path |
str |
varies by route | Custom path for the route |
status_code |
int |
varies by route | HTTP status code for successful responses |
auth |
Any |
NOT_SET | Authentication class or instance |
throttle |
BaseThrottle \| List[BaseThrottle] |
NOT_SET | Throttle class(es) for rate limiting |
response |
Any |
NOT_SET | Custom response configuration |
url_name |
str \| None |
None | Django URL name for the route |
description |
str \| None |
None | Detailed description for OpenAPI docs |
operation_id |
str \| None |
None | Custom operation ID for OpenAPI |
summary |
str \| None |
varies by route | Short summary for OpenAPI docs |
tags |
List[str] \| None |
None | Tags for grouping in OpenAPI docs |
deprecated |
bool \| None |
None | Mark route as deprecated in OpenAPI |
by_alias |
bool |
False | Use schema field aliases in response |
exclude_unset |
bool |
False | Exclude unset fields from response |
exclude_defaults |
bool |
False | Exclude fields with default values |
exclude_none |
bool |
False | Exclude None fields from response |
include_in_schema |
bool |
True | Include route in OpenAPI schema |
permissions |
List[BasePermission] |
None | Permission classes for the route |
openapi_extra |
Dict[str, Any] \| None |
None | Extra OpenAPI schema properties |
Route-Specific Parameters
Create Route (create_route_info)
custom_handler: Custom handler function to override default create logic
Update/Patch Routes (update_route_info, patch_route_info)
object_getter: Custom function to retrieve the objectcustom_handler: Custom handler function to override default update/patch logic
Find One Route (find_one_route_info)
object_getter: Custom function to retrieve the object
Delete Route (delete_route_info)
object_getter: Custom function to retrieve the objectcustom_handler: Custom handler function to override default delete logic
List Route (list_route_info)
queryset_getter: Custom function to retrieve the querysetpagination_response_schema: Custom pagination response schema
Basic Example
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
# Customize specific route configurations
create_route_info={
"summary": "Create a new event",
"description": "Creates a new event with the provided data",
"tags": ["events"],
"deprecated": False,
},
list_route_info={
"summary": "List all events",
"description": "Retrieves a paginated list of all events",
"tags": ["events"],
},
find_one_route_info={
"summary": "Get event details",
"description": "Retrieves details of a specific event",
"tags": ["events"],
}
)
Advanced Configuration Example
from ninja_extra import status
from ninja_extra.permissions import IsAuthenticated, IsAdminUser
from ninja_extra.throttling import AnonRateThrottle
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
create_route_info={
"summary": "Create a new event",
"description": "Creates a new event with the provided data",
"tags": ["events", "management"],
"status_code": status.HTTP_201_CREATED,
"permissions": [IsAuthenticated],
"throttle": AnonRateThrottle(),
"exclude_none": True,
"openapi_extra": {
"requestBody": {
"content": {
"application/json": {
"examples": {
"example1": {
"summary": "Conference event",
"value": {
"title": "Tech Conference 2024",
"start_date": "2024-06-01",
"end_date": "2024-06-03"
}
}
}
}
}
}
}
},
update_route_info={
"summary": "Update event",
"permissions": [IsAuthenticated, IsAdminUser],
"exclude_unset": True,
},
delete_route_info={
"summary": "Delete an event",
"permissions": [IsAdminUser],
"status_code": status.HTTP_204_NO_CONTENT,
}
)
Async Routes Configuration
Enable async routes and configure async behavior:
@api_controller("/events")
class AsyncEventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
# Async-specific configurations
async_routes=True,
schema_config=ModelSchemaConfig(
read_only_fields=["id"],
depth=1
)
)
# Custom async service implementation
service = AsyncEventModelService(model=Event)
Configuration Inheritance
ModelConfig also support configuration inheritance:
from ninja_extra.controllers import ModelConfig
class BaseModelConfig(ModelConfig):
async_routes = True
schema_config = ModelSchemaConfig(
read_only_fields=["id", "created_at", "updated_at"],
depth=1
)
@api_controller("/events")
class EventModelController(ModelControllerBase):
model_config = BaseModelConfig(
model=Event,
# Override or extend base configuration
allowed_routes=["list", "find_one"]
)
Best Practices
-
Schema Configuration:
- Always specify
read_only_fieldsfor auto-generated fields - Use
depthcarefully as it can impact performance - Consider using
excludefor sensitive fields
- Always specify
-
Route Configuration:
- Limit
allowed_routesto only necessary endpoints - Provide meaningful summaries and descriptions
- Use tags for API organization
- Limit
-
Pagination:
- Always set reasonable limits
- Consider your data size when choosing pagination class
- Use appropriate page sizes for your use case
-
Filtering:
- Use
FilterSchemato provide flexible filtering on list endpoints - Leverage
FilterLookupfor complex database lookups (e.g.,__icontains,__gte) - Consider indexing filtered fields in your database for performance
- Document available filters in your API documentation
- Use
-
Async Support:
- Enable
async_routeswhen using async database operations - Implement custom async services for complex operations
- Consider performance implications of async operations
- Enable