Skip to content

NinjaAPI

Ninja API

Source code in ninja/main.py
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
class NinjaAPI:
    """
    Ninja API
    """

    _registry: List[str] = []

    def __init__(
        self,
        *,
        title: str = "NinjaAPI",
        version: str = "1.0.0",
        description: str = "",
        openapi_url: Optional[str] = "/openapi.json",
        docs_url: Optional[str] = "/docs",
        docs_decorator: Optional[Callable[[TCallable], TCallable]] = None,
        urls_namespace: Optional[str] = None,
        csrf: bool = False,
        auth: Optional[Union[Sequence[Callable], Callable, NOT_SET_TYPE]] = NOT_SET,
        renderer: Optional[BaseRenderer] = None,
        parser: Optional[Parser] = None,
        default_router: Optional[Router] = None,
    ):
        """
        Args:
            title: A title for the api.
            description: A description for the api.
            version: The API version.
            urls_namespace: The Django URL namespace for the API. If not provided, the namespace will be ``"api-" + self.version``.
            openapi_url: The relative URL to serve the openAPI spec.
            docs_url: The relative URL to serve the API docs.
            csrf: Require a CSRF token for unsafe request types. See <a href="../csrf">CSRF</a> docs.
            auth (Callable | Sequence[Callable] | NOT_SET | None): Authentication class
            renderer: Default response renderer
            parser: Default request parser
        """
        self.title = title
        self.version = version
        self.description = description
        self.openapi_url = openapi_url
        self.docs_url = docs_url
        self.docs_decorator = docs_decorator
        self.urls_namespace = urls_namespace or f"api-{self.version}"
        self.csrf = csrf
        self.renderer = renderer or JSONRenderer()
        self.parser = parser or Parser()

        self._exception_handlers: Dict[Exc, ExcHandler] = {}
        self.set_default_exception_handlers()

        self.auth: Optional[Union[Sequence[Callable], NOT_SET_TYPE]]

        if callable(auth):
            self.auth = [auth]
        else:
            self.auth = auth

        self._routers: List[Tuple[str, Router]] = []
        self.default_router = default_router or Router()
        self.add_router("", self.default_router)

    def get(
        self,
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        """
        `GET` operation. See <a href="../operations-parameters">operations
        parameters</a> reference.
        """
        return self.default_router.get(
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def post(
        self,
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        """
        `POST` operation. See <a href="../operations-parameters">operations
        parameters</a> reference.
        """
        return self.default_router.post(
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def delete(
        self,
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        """
        `DELETE` operation. See <a href="../operations-parameters">operations
        parameters</a> reference.
        """
        return self.default_router.delete(
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def patch(
        self,
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        """
        `PATCH` operation. See <a href="../operations-parameters">operations
        parameters</a> reference.
        """
        return self.default_router.patch(
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def put(
        self,
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        """
        `PUT` operation. See <a href="../operations-parameters">operations
        parameters</a> reference.
        """
        return self.default_router.put(
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def api_operation(
        self,
        methods: List[str],
        path: str,
        *,
        auth: Any = NOT_SET,
        response: Any = NOT_SET,
        operation_id: Optional[str] = None,
        summary: Optional[str] = None,
        description: Optional[str] = None,
        tags: Optional[List[str]] = None,
        deprecated: Optional[bool] = None,
        by_alias: bool = False,
        exclude_unset: bool = False,
        exclude_defaults: bool = False,
        exclude_none: bool = False,
        url_name: Optional[str] = None,
        include_in_schema: bool = True,
    ) -> Callable[[TCallable], TCallable]:
        return self.default_router.api_operation(
            methods,
            path,
            auth=auth is NOT_SET and self.auth or auth,
            response=response,
            operation_id=operation_id,
            summary=summary,
            description=description,
            tags=tags,
            deprecated=deprecated,
            by_alias=by_alias,
            exclude_unset=exclude_unset,
            exclude_defaults=exclude_defaults,
            exclude_none=exclude_none,
            url_name=url_name,
            include_in_schema=include_in_schema,
        )

    def add_router(
        self,
        prefix: str,
        router: Router,
        *,
        auth: Any = NOT_SET,
        tags: Optional[List[str]] = None,
        parent_router: Router = None,
    ) -> None:
        if auth is not NOT_SET:
            router.auth = auth
        if tags is not None:
            router.tags = tags

        if parent_router:
            parent_prefix = next(
                (path for path, r in self._routers if r is parent_router), None
            )  # pragma: no cover
            assert parent_prefix is not None
            prefix = normalize_path("/".join((parent_prefix, prefix))).lstrip("/")

        self._routers.extend(router.build_routers(prefix))
        router.set_api_instance(self)

    @property
    def urls(self) -> Tuple[List[Union[URLResolver, URLPattern]], str, str]:
        """
        str: URL configuration

        Returns:

            Django URL configuration
        """
        self._validate()
        return (
            self._get_urls(),
            "ninja",
            self.urls_namespace.split(":")[-1],
            # ^ if api included into nested urls, we only care about last bit here
        )

    def _get_urls(self) -> List[Union[URLResolver, URLPattern]]:
        result = get_openapi_urls(self)

        for prefix, router in self._routers:
            result.extend(router.urls_paths(prefix))

        result.append(get_root_url(self))
        return result

    @property
    def root_path(self) -> str:
        name = f"{self.urls_namespace}:api-root"
        return reverse(name)

    def create_response(
        self,
        request: HttpRequest,
        data: Any,
        *,
        status: int = None,
        temporal_response: HttpResponse = None,
    ) -> HttpResponse:
        if temporal_response:
            status = temporal_response.status_code
        assert status

        content = self.renderer.render(request, data, response_status=status)

        if temporal_response:
            response = temporal_response
            response.content = content
        else:
            response = HttpResponse(
                content, status=status, content_type=self.get_content_type()
            )

        return response

    def create_temporal_response(self, request: HttpRequest) -> HttpResponse:
        return HttpResponse("", content_type=self.get_content_type())

    def get_content_type(self) -> str:
        return "{}; charset={}".format(self.renderer.media_type, self.renderer.charset)

    def get_openapi_schema(self, path_prefix: Optional[str] = None) -> OpenAPISchema:
        if path_prefix is None:
            path_prefix = self.root_path
        return get_schema(api=self, path_prefix=path_prefix)

    def get_openapi_operation_id(self, operation: "Operation") -> str:
        name = operation.view_func.__name__
        module = operation.view_func.__module__
        return (module + "_" + name).replace(".", "_")

    def get_operation_url_name(self, operation: "Operation", router: Router) -> str:
        """
        Get the default URL name to use for an operation if it wasn't
        explicitly provided.
        """
        return operation.view_func.__name__

    def add_exception_handler(
        self, exc_class: Type[Exception], handler: ExcHandler
    ) -> None:
        assert issubclass(exc_class, Exception)
        self._exception_handlers[exc_class] = handler

    def exception_handler(self, exc_class: Type[Exception]) -> Callable:
        def decorator(func: Callable) -> Callable:
            self.add_exception_handler(exc_class, func)
            return func

        return decorator

    def set_default_exception_handlers(self) -> None:
        set_default_exc_handlers(self)

    def on_exception(self, request: HttpRequest, exc: Exc) -> HttpResponse:
        handler = self._lookup_exception_handler(exc)
        if handler is None:
            raise exc
        return handler(request, exc)

    def _lookup_exception_handler(self, exc: Exc) -> Optional[ExcHandler]:
        for cls in type(exc).__mro__:
            if cls in self._exception_handlers:
                return self._exception_handlers[cls]

        return None

    def _validate(self) -> None:
        from ninja.security import APIKeyCookie

        # 1) urls namespacing validation
        skip_registry = os.environ.get("NINJA_SKIP_REGISTRY", False)
        if (
            not skip_registry
            and self.urls_namespace in NinjaAPI._registry
            and not debug_server_url_reimport()
        ):
            msg = f"""
Looks like you created multiple NinjaAPIs or TestClients
To let ninja distinguish them you need to set either unique version or urls_namespace
 - NinjaAPI(..., version='2.0.0')
 - NinjaAPI(..., urls_namespace='otherapi')
Already registered: {NinjaAPI._registry}
"""
            raise ConfigError(msg.strip())
        NinjaAPI._registry.append(self.urls_namespace)

        # 2) csrf
        if self.csrf is False:
            for _prefix, router in self._routers:
                for path_operation in router.path_operations.values():
                    for operation in path_operation.operations:
                        for auth in operation.auth_callbacks:
                            if isinstance(auth, APIKeyCookie):
                                raise ConfigError(
                                    "Cookie Authentication must be used with CSRF. Please use NinjaAPI(csrf=True)"
                                )

__init__

Parameters:

Name Type Description Default
title str

A title for the api.

'NinjaAPI'
description str

A description for the api.

''
version str

The API version.

'1.0.0'
urls_namespace Optional[str]

The Django URL namespace for the API. If not provided, the namespace will be "api-" + self.version.

None
openapi_url Optional[str]

The relative URL to serve the openAPI spec.

'/openapi.json'
docs_url Optional[str]

The relative URL to serve the API docs.

'/docs'
csrf bool

Require a CSRF token for unsafe request types. See CSRF docs.

False
auth Callable | Sequence[Callable] | NOT_SET | None

Authentication class

NOT_SET
renderer Optional[BaseRenderer]

Default response renderer

None
parser Optional[Parser]

Default request parser

None
Source code in ninja/main.py
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
def __init__(
    self,
    *,
    title: str = "NinjaAPI",
    version: str = "1.0.0",
    description: str = "",
    openapi_url: Optional[str] = "/openapi.json",
    docs_url: Optional[str] = "/docs",
    docs_decorator: Optional[Callable[[TCallable], TCallable]] = None,
    urls_namespace: Optional[str] = None,
    csrf: bool = False,
    auth: Optional[Union[Sequence[Callable], Callable, NOT_SET_TYPE]] = NOT_SET,
    renderer: Optional[BaseRenderer] = None,
    parser: Optional[Parser] = None,
    default_router: Optional[Router] = None,
):
    """
    Args:
        title: A title for the api.
        description: A description for the api.
        version: The API version.
        urls_namespace: The Django URL namespace for the API. If not provided, the namespace will be ``"api-" + self.version``.
        openapi_url: The relative URL to serve the openAPI spec.
        docs_url: The relative URL to serve the API docs.
        csrf: Require a CSRF token for unsafe request types. See <a href="../csrf">CSRF</a> docs.
        auth (Callable | Sequence[Callable] | NOT_SET | None): Authentication class
        renderer: Default response renderer
        parser: Default request parser
    """
    self.title = title
    self.version = version
    self.description = description
    self.openapi_url = openapi_url
    self.docs_url = docs_url
    self.docs_decorator = docs_decorator
    self.urls_namespace = urls_namespace or f"api-{self.version}"
    self.csrf = csrf
    self.renderer = renderer or JSONRenderer()
    self.parser = parser or Parser()

    self._exception_handlers: Dict[Exc, ExcHandler] = {}
    self.set_default_exception_handlers()

    self.auth: Optional[Union[Sequence[Callable], NOT_SET_TYPE]]

    if callable(auth):
        self.auth = [auth]
    else:
        self.auth = auth

    self._routers: List[Tuple[str, Router]] = []
    self.default_router = default_router or Router()
    self.add_router("", self.default_router)

delete

DELETE operation. See operations parameters reference.

Source code in ninja/main.py
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
def delete(
    self,
    path: str,
    *,
    auth: Any = NOT_SET,
    response: Any = NOT_SET,
    operation_id: Optional[str] = None,
    summary: Optional[str] = None,
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    deprecated: Optional[bool] = None,
    by_alias: bool = False,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    url_name: Optional[str] = None,
    include_in_schema: bool = True,
) -> Callable[[TCallable], TCallable]:
    """
    `DELETE` operation. See <a href="../operations-parameters">operations
    parameters</a> reference.
    """
    return self.default_router.delete(
        path,
        auth=auth is NOT_SET and self.auth or auth,
        response=response,
        operation_id=operation_id,
        summary=summary,
        description=description,
        tags=tags,
        deprecated=deprecated,
        by_alias=by_alias,
        exclude_unset=exclude_unset,
        exclude_defaults=exclude_defaults,
        exclude_none=exclude_none,
        url_name=url_name,
        include_in_schema=include_in_schema,
    )

get

GET operation. See operations parameters reference.

Source code in ninja/main.py
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
def get(
    self,
    path: str,
    *,
    auth: Any = NOT_SET,
    response: Any = NOT_SET,
    operation_id: Optional[str] = None,
    summary: Optional[str] = None,
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    deprecated: Optional[bool] = None,
    by_alias: bool = False,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    url_name: Optional[str] = None,
    include_in_schema: bool = True,
) -> Callable[[TCallable], TCallable]:
    """
    `GET` operation. See <a href="../operations-parameters">operations
    parameters</a> reference.
    """
    return self.default_router.get(
        path,
        auth=auth is NOT_SET and self.auth or auth,
        response=response,
        operation_id=operation_id,
        summary=summary,
        description=description,
        tags=tags,
        deprecated=deprecated,
        by_alias=by_alias,
        exclude_unset=exclude_unset,
        exclude_defaults=exclude_defaults,
        exclude_none=exclude_none,
        url_name=url_name,
        include_in_schema=include_in_schema,
    )

get_operation_url_name

Get the default URL name to use for an operation if it wasn't explicitly provided.

Source code in ninja/main.py
426
427
428
429
430
431
def get_operation_url_name(self, operation: "Operation", router: Router) -> str:
    """
    Get the default URL name to use for an operation if it wasn't
    explicitly provided.
    """
    return operation.view_func.__name__

patch

PATCH operation. See operations parameters reference.

Source code in ninja/main.py
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
def patch(
    self,
    path: str,
    *,
    auth: Any = NOT_SET,
    response: Any = NOT_SET,
    operation_id: Optional[str] = None,
    summary: Optional[str] = None,
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    deprecated: Optional[bool] = None,
    by_alias: bool = False,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    url_name: Optional[str] = None,
    include_in_schema: bool = True,
) -> Callable[[TCallable], TCallable]:
    """
    `PATCH` operation. See <a href="../operations-parameters">operations
    parameters</a> reference.
    """
    return self.default_router.patch(
        path,
        auth=auth is NOT_SET and self.auth or auth,
        response=response,
        operation_id=operation_id,
        summary=summary,
        description=description,
        tags=tags,
        deprecated=deprecated,
        by_alias=by_alias,
        exclude_unset=exclude_unset,
        exclude_defaults=exclude_defaults,
        exclude_none=exclude_none,
        url_name=url_name,
        include_in_schema=include_in_schema,
    )

post

POST operation. See operations parameters reference.

Source code in ninja/main.py
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def post(
    self,
    path: str,
    *,
    auth: Any = NOT_SET,
    response: Any = NOT_SET,
    operation_id: Optional[str] = None,
    summary: Optional[str] = None,
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    deprecated: Optional[bool] = None,
    by_alias: bool = False,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    url_name: Optional[str] = None,
    include_in_schema: bool = True,
) -> Callable[[TCallable], TCallable]:
    """
    `POST` operation. See <a href="../operations-parameters">operations
    parameters</a> reference.
    """
    return self.default_router.post(
        path,
        auth=auth is NOT_SET and self.auth or auth,
        response=response,
        operation_id=operation_id,
        summary=summary,
        description=description,
        tags=tags,
        deprecated=deprecated,
        by_alias=by_alias,
        exclude_unset=exclude_unset,
        exclude_defaults=exclude_defaults,
        exclude_none=exclude_none,
        url_name=url_name,
        include_in_schema=include_in_schema,
    )

put

PUT operation. See operations parameters reference.

Source code in ninja/main.py
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
def put(
    self,
    path: str,
    *,
    auth: Any = NOT_SET,
    response: Any = NOT_SET,
    operation_id: Optional[str] = None,
    summary: Optional[str] = None,
    description: Optional[str] = None,
    tags: Optional[List[str]] = None,
    deprecated: Optional[bool] = None,
    by_alias: bool = False,
    exclude_unset: bool = False,
    exclude_defaults: bool = False,
    exclude_none: bool = False,
    url_name: Optional[str] = None,
    include_in_schema: bool = True,
) -> Callable[[TCallable], TCallable]:
    """
    `PUT` operation. See <a href="../operations-parameters">operations
    parameters</a> reference.
    """
    return self.default_router.put(
        path,
        auth=auth is NOT_SET and self.auth or auth,
        response=response,
        operation_id=operation_id,
        summary=summary,
        description=description,
        tags=tags,
        deprecated=deprecated,
        by_alias=by_alias,
        exclude_unset=exclude_unset,
        exclude_defaults=exclude_defaults,
        exclude_none=exclude_none,
        url_name=url_name,
        include_in_schema=include_in_schema,
    )

urls property

str: URL configuration

Returns:

Type Description
Tuple[List[Union[URLResolver, URLPattern]], str, str]

Django URL configuration

Source code in ninja/main.py
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
@property
def urls(self) -> Tuple[List[Union[URLResolver, URLPattern]], str, str]:
    """
    str: URL configuration

    Returns:

        Django URL configuration
    """
    self._validate()
    return (
        self._get_urls(),
        "ninja",
        self.urls_namespace.split(":")[-1],
        # ^ if api included into nested urls, we only care about last bit here
    )