How to put Controller under router
I'm wondering how I register a controller to a router, this doesn't seem to work:
# trying to register a controller on a router doesnt work:
router.register_controllers(EventModelController)
# trying to nest under an existing router also doesn't work:
router.add_router('event', EventModelController)
I have the following simplified setup:
api/urls.py:
api = NinjaExtraAPI(auth=django_auth)
api.add_router('/auth/', 'api.routes_auth.router')
api.add_router('/models/', 'api.routes_models.router')
urlpatterns = [
path("v1/", api.urls),
path("v1", RedirectView.as_view(url='/api/v1/docs')),
path("", RedirectView.as_view(url='/api/v1/docs')),
]
api/routes_auth.py:
router = Router(tags=['Authentication'])
@router.post("/get_token", auth=None, summary='Get an API token for a given user & pass')
def get_token(request, auth_data: PasswordAuthSchema):
...
@router.post("/validate_token", auth=None, summary='Validate a given API token')
def validate_token(request, token_data: TokenAuthSchema):
...
api/routes_models.py:
from core.models import Event
...
router = Router(tags=['Core Data Models'])
@api_controller()
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
schema_config=ModelSchemaConfig(read_only_fields=["id"]),
)
# this fails however:
router.add_router('event', EventModelController)
So my question is, how does one properly nest a controller under an existing router? (without direct access to the top-level api object)
@pirate Controllers can not be registered to routers because it does not follow a full Ninja router interface.
Also, controllers do not support nesting with routers or other controllers.
But if you want to lazy load the controllers, you can do the following for now:
from django.utils.module_loading import import_string
...
api = NinjaExtraAPI(auth=django_auth)
api.register_controllers(
import_string('api.routes_models.EventModelController'),
)
api.add_router('/auth/', 'api.routes_auth.router')
api.add_router('/models/', 'api.routes_models.router')
urlpatterns = [
path("v1/", api.urls),
path("v1", RedirectView.as_view(url='/api/v1/docs')),
path("", RedirectView.as_view(url='/api/v1/docs')),
]
I will work on a better lazy loading setup for controllers.
The issue is I need the controller to live below a router because I'm mixing-and-matching a bunch of normal Django-ninja router routes next to the controller at the same level.
E.g.
- /api/models = Django-ninja router
- /api/models/Event -> EventController (ninja-extra)
- /api/models/Foo/search -> Django-ninja router
- /api/models/Bar -> Django-ninja router
(The context is I'm using Django-extra not for the class based routes, but just for the automatic ModelController on models I'm too lazy to implement myself. I do my own function based CRUD interfaces on the important ones, but for less important ones I was hoping to get CRUD interfaces for free)
You can still use your event controller without mixing it with a router. If I am to implement this, with your route paths setup, I would do the following:
api/urls.py:
api = NinjaExtraAPI(auth=django_auth)
api.register_controllers(
import_string('api.routes_models.EventModelController'),
)
api.add_router('/auth/', 'api.routes_auth.router')
api.add_router('/models/', 'api.routes_models.router')
urlpatterns = [
path("v1/", api.urls),
path("v1", RedirectView.as_view(url='/api/v1/docs')),
path("", RedirectView.as_view(url='/api/v1/docs')),
]
api/routes_auth.py:
router = Router(tags=['Authentication'])
@router.post("/get_token", auth=None, summary='Get an API token for a given user & pass')
def get_token(request, auth_data: PasswordAuthSchema):
...
@router.post("/validate_token", auth=None, summary='Validate a given API token')
def validate_token(request, token_data: TokenAuthSchema):
...
api/routes_models.py:
from core.models import Event
...
# specifies the path as a prefix to controller routes. just as you do in api.add_router("/model/event", router)
@api_controller("/model/events/")
class EventModelController(ModelControllerBase):
model_config = ModelConfig(
model=Event,
schema_config=ModelSchemaConfig(read_only_fields=["id"]),
)