### UsersController Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md An example of a UsersController demonstrating GET and POST routes with request/response schemas and authentication. ```APIDOC ## APIController Decorator Example ```python import typing from ninja_extra import api_controller, ControllerBase, permissions, route from django.contrib.auth.models import User from ninja.security import APIKeyQuery from ninja import ModelSchema class UserSchema(ModelSchema): class Config: model = User model_fields = ['username', 'email', 'first_name'] @api_controller('users/', auth=[APIKeyQuery()], permissions=[permissions.IsAuthenticated]) class UsersController(ControllerBase): @route.get('', response={200: typing.List[UserSchema]}) def get_users(self): # Logic to handle GET request to the /users endpoint users = User.objects.all() return users @route.post('create/', response={200: UserSchema}) def create_user(self, payload: UserSchema): # Logic to handle POST request to the /users endpoint new_user = User.objects.create( username=payload.username, email=payload.email, first_name=payload.first_name, ) new_user.set_password('password') return new_user ``` In the above code, we have defined a controller called `UsersController` using the `api_controller` decorator. The decorator is applied to the class and takes two arguments, the URL endpoint `/users` and `auth` and `permission` classes. And `get_users` and `create_user` are route function that handles GET `/users` and POST `/users/create` incoming request. ``` -------------------------------- ### Initialize NinjaExtraAPI and define a GET endpoint Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/index.md Initialize NinjaExtraAPI and define a simple GET endpoint '/hello' that returns a string. This is the basic setup for your API. ```python from ninja_extra import NinjaExtraAPI api = NinjaExtraAPI() # function definition using Django-Ninja default router @api.get("/hello") def hello(request): return "Hello world" ``` -------------------------------- ### Install django-ninja-extra Source: https://github.com/eadwincode/django-ninja-extra/blob/master/README.md Install the package using pip. This is the first step to using django-ninja-extra. ```bash pip install django-ninja-extra ``` -------------------------------- ### Install Development Dependencies and Pre-commit Hooks Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/contribution.md Run this command to install all necessary development libraries and set up pre-commit hooks for the project. ```bash make install-full ``` -------------------------------- ### Basic Controller Setup Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md Demonstrates how to define a basic controller using ControllerBase and the api_controller decorator. ```APIDOC ## ControllerBase The `ControllerBase` class is the base class for all controllers in Django Ninja Extra. It provides the core functionality for handling requests, validating input, and returning responses in a class-based approach. ```python from ninja_extra import ControllerBase, api_controller @api_controller('/users') class UserControllerBase(ControllerBase): ... ``` ## APIController Decorator The `api_controller` decorator is used to define a class-based controller in Django Ninja Extra. It is applied to a ControllerBase class and takes several arguments to configure the routes and functionality of the controller. ``` -------------------------------- ### Development Settings Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/dependency-injection/testing.md Configure development settings to use real service implementations by specifying the module in NINJA_EXTRA. ```python from .base import * NINJA_EXTRA = { 'INJECTOR_MODULES': [ 'your_app.modules.TodoModule' # Uses real implementation ] } ``` -------------------------------- ### Install Django Ninja Extra and Ninja Schema Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/01_getting_started.md Install the necessary packages using pip. Ninja Schema is recommended for schema generation. ```bash pip install django-ninja-extra ninja-schema ``` -------------------------------- ### Testing Settings Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/dependency-injection/testing.md Configure testing settings to use mock service implementations by specifying the mock module in NINJA_EXTRA. ```python from .base import * NINJA_EXTRA = { 'INJECTOR_MODULES': [ 'your_app.modules.MockTodoModule' # Uses mock implementation ] } ``` -------------------------------- ### Basic API Setup with Function-Based and Class-Based Endpoints Source: https://github.com/eadwincode/django-ninja-extra/blob/master/README.md Demonstrates setting up a basic API with both function-based and class-based endpoints using NinjaExtraAPI and api_controller. ```python from ninja_extra import NinjaExtraAPI, api_controller, http_get api = NinjaExtraAPI() # Function-based endpoint example @api.get("/hello", tags=['Basic']) def hello(request, name: str = "World"): return {"message": f"Hello, {name}!"} # Class-based controller example @api_controller('/math', tags=['Math']) class MathController: @http_get('/add') def add(self, a: int, b: int): """Add two numbers""" return {"result": a + b} @http_get('/multiply') def multiply(self, a: int, b: int): """Multiply two numbers""" return {"result": a * b} # Register your controllers api.register_controllers(MathController) ``` -------------------------------- ### Install ninja-schema Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Install the ninja-schema package using pip to enable automatic schema generation for Model Controllers. ```shell pip install ninja-schema ``` -------------------------------- ### Basic Throttling Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/throttling.md Applies default UserRateThrottle and AnonRateThrottle to an endpoint. Note: This example won't be throttled due to default scope settings. ```python from ninja_extra import NinjaExtraAPI from ninja_extra.throttling import UserRateThrottle, AnonRateThrottle api = NinjaExtraAPI() @api.get('/users', throttle=[AnonRateThrottle(), UserRateThrottle()]) def my_throttled_endpoint(request): return 'foo' ``` -------------------------------- ### Install flit Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/contribution.md Install the 'flit' package manager globally. This is a prerequisite for managing project dependencies. ```bash pip install flit ``` -------------------------------- ### AllowAny Permission Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Use AllowAny to grant unrestricted access to an API controller. No special setup is required beyond importing the permission class. ```python from ninja_extra import permissions, api_controller, http_get @api_controller(permissions=[permissions.AllowAny]) class PublicController: @http_get("/public") def public_endpoint(self): return {"message": "This endpoint is public"} ``` -------------------------------- ### Create a new Django project Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/index.md Start a new Django project if you don't have an existing one. This command creates the project structure. ```bash django-admin startproject myproject ``` -------------------------------- ### APIController Decorator with Auth and Permissions Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md Illustrates how to use the api_controller decorator to define a controller with specific authentication and permission classes, and includes examples of GET and POST routes. ```python import typing from ninja_extra import api_controller, ControllerBase, permissions, route from django.contrib.auth.models import User from ninja.security import APIKeyQuery from ninja import ModelSchema class UserSchema(ModelSchema): class Config: model = User model_fields = ['username', 'email', 'first_name'] @api_controller('users/', auth=[APIKeyQuery()], permissions=[permissions.IsAuthenticated]) class UsersController(ControllerBase): @route.get('', response={200: typing.List[UserSchema]}) def get_users(self): # Logic to handle GET request to the /users endpoint users = User.objects.all() return users @route.post('create/', response={200: UserSchema}) def create_user(self, payload: UserSchema): # Logic to handle POST request to the /users endpoint new_user = User.objects.create( username=payload.username, email=payload.email, first_name=payload.first_name, ) new_user.set_password('password') return new_user ``` -------------------------------- ### Basic Dependency Injection in Controller Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/dependency-injection/index.md Demonstrates a simple dependency injection setup where a UserService is injected into a UserController. Type annotation for the injected service in the constructor is mandatory. ```python from ninja_extra import api_controller, http_get from injector import inject class UserService: def get_user_count(self) -> int: return 42 # Example implementation @api_controller("/users") class UserController: @inject def __init__(self, user_service: UserService): # Type annotation is required self.user_service = user_service @http_get("/count") def get_count(self): return {"count": self.user_service.get_user_count()} ``` -------------------------------- ### Implementing User Listing with PageNumberPaginationExtra Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/pagination.md This example demonstrates how to use `PageNumberPaginationExtra` with a custom page size for listing users. It also shows a separate route using the default `LimitOffsetPagination`. ```python from typing import List from ninja_extra.pagination import ( paginate, PageNumberPaginationExtra, PaginatedResponseSchema ) from ninja_extra import api_controller, route, NinjaExtraAPI from ninja import ModelSchema from django.contrib.auth import get_user_model user_model = get_user_model() class UserSchema(ModelSchema): class Config: model = user_model model_fields = ['username', 'email'] @api_controller('/users') class UserController: @route.get('', response=PaginatedResponseSchema[UserSchema]) @paginate(PageNumberPaginationExtra, page_size=50) def get_users(self): return user_model.objects.all() @route.get('/limit', response=List[UserSchema]) @paginate def get_users_with_limit(self): # this will use default paginator class - ninja_extra.pagination.LimitOffsetPagination return user_model.objects.all() api = NinjaExtraAPI(title='Pagination Test') api.register_controllers(UserController) ``` -------------------------------- ### Custom Async Permission Class Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Define a custom asynchronous permission by inheriting from `AsyncBasePermission` and implementing the `has_permission_async` and `has_object_permission_async` methods. This example checks if the user is authenticated and, for object-level permissions, if the user is staff or the owner of the object. ```python from django.contrib.auth.models import User from asgiref.sync import sync_to_async from ninja_extra import api_controller, http_get, http_post, ControllerBase from ninja_extra.permissions import AsyncBasePermission, IsAuthenticated, AllowAny # Custom async permission class IsStaffOrOwnerAsync(AsyncBasePermission): async def has_permission_async(self, request, controller): return request.user.is_authenticated async def has_object_permission_async(self, request, controller, obj): # Either the user is staff or owns the object return request.user.is_staff or obj.owner_id == request.user.id # Controller using mixed permissions @api_controller("/users", permissions=[IsAuthenticated]) class UserController(ControllerBase): @http_get("/", permissions=[AllowAny]) async def list_users(self, request): # Public endpoint users = await sync_to_async(list)(User.objects.values('id', 'username')[:10]) return users @http_get("/{user_id}") async def get_user(self, request, user_id: int): # Protected by IsAuthenticated from the controller user = await self.aget_object_or_exception(User, id=user_id) return {"id": user.id, "username": user.username} @http_post("/update/{user_id}", permissions=[IsStaffOrOwnerAsync()]) async def update_user(self, request, user_id: int, data: dict): # Protected by custom async permission user = await self.aget_object_or_exception(User, id=user_id) # Update user data return {"status": "success"} ``` -------------------------------- ### Basic Ordering by Specified Fields Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/ordering.md This example demonstrates how to use the `ordering` decorator to allow users to sort API results by 'username' or 'email'. The `Ordering` class is used with explicitly defined `ordering_fields`. ```python from typing import List from ninja_extra.ordering import ordering, Ordering from ninja_extra import api_controller, route, NinjaExtraAPI from ninja import ModelSchema from django.contrib.auth import get_user_model user_model = get_user_model() class UserSchema(ModelSchema): class Config: model = user_model model_fields = ['username', 'email'] @api_controller('/users') class UserController: @route.get('', response=List[UserSchema]) @ordering(Ordering, ordering_fields=['username', 'email']) def get_users(self): return user_model.objects.all() api = NinjaExtraAPI(title='Ordering Test') api.register_controllers(UserController) ``` -------------------------------- ### Testing Controller with Async Permissions Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Integrate and test controllers that use asynchronous permissions with `TestAsyncClient`. This example shows how to simulate requests with different user types (anonymous and authenticated) and verify the expected HTTP status codes. ```python @pytest.mark.asyncio async def test_controller_with_permissions(): @api_controller("/test") class TestController(ControllerBase): @http_get("/protected", permissions=[CustomAsyncPermission()]) async def protected_route(self): return {"success": True} # Create async test client client = TestAsyncClient(TestController) # Test with anonymous user response = await client.get("/protected", user=AnonymousUser()) assert response.status_code == 403 # Test with authenticated user auth_user = Mock(is_authenticated=True) response = await client.get("/protected", user=auth_user) assert response.status_code == 200 assert response.json() == {"success": True} ``` -------------------------------- ### Define API Controller with Query Parameters Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/query.md This snippet shows how to define an API controller with a GET route that accepts 'limit' and 'offset' as query parameters. Default values are provided for these parameters. ```python from ninja import constants from ninja_extra import api_controller, route @api_controller('', tags=['My Operations'], auth=constants.NOT_SET, permissions=[]) class MyAPIController: weapons = ["Ninjato", "Shuriken", "Katana", "Kama", "Kunai", "Naginata", "Yari"] @route.get("/weapons") def list_weapons(self, limit: int = 10, offset: int = 0): return self.weapons[offset: offset + limit] ``` -------------------------------- ### Global HTTP Bearer Authentication for All Routes Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/authentication.md This example shows how to apply global authentication to all routes defined within an API controller or the main API instance. All routes will require the specified authentication. ```Python from ninja_extra import NinjaExtraAPI from ninja.security import HttpBearer class GlobalAuth(HttpBearer): def authenticate(self, request, token): if token == "supersecret": return token api = NinjaExtraAPI(auth=GlobalAuth()) ``` -------------------------------- ### Using Ninja LimitOffsetPagination with Response Schema Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/pagination.md When using `ninja_extra.pagination.LimitOffsetPagination`, ensure you use `NinjaPaginationResponseSchema` as the pagination response schema wrapper. This example demonstrates setting up a route to list users with this pagination strategy. ```python from ninja_extra.schemas import NinjaPaginationResponseSchema ... @route.get('', response=NinjaPaginationResponseSchema[UserSchema]) @paginate() def list_items(self): return item_model.objects.all() ``` -------------------------------- ### Create EventModelController Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Defines a ModelController for the Event model, configuring routes and schema generation. Ensure ninja-schema is installed for schema generation. ```python from ninja_extra import ( ModelConfig, ModelControllerBase, ModelSchemaConfig, api_controller, NinjaExtraAPI ) from .models import Event @api_controller("/events") class EventModelController(ModelControllerBase): model_config = ModelConfig( model=Event, schema_config=ModelSchemaConfig( read_only_fields=["id", "category"], # if you want to extra configuration to the generated schemas # extra_config_dict={ # 'title': 'EventCustomTitle', # 'populate_by_name': True # } ), ) api = NinjaExtraAPI() api.register_controllers(EventModelController) ``` -------------------------------- ### Applying Injected Permissions to API Endpoints Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Apply dynamically created injected permissions to API endpoints. This example shows how to apply 'basic', 'premium', and combined permissions. ```python @api_controller('features') class FeatureController(ControllerBase): @http_get('basic/', permissions=[FeaturePermission.create_as("basic")]) async def basic_feature(self): return {"feature": "basic"} @http_get('premium/', permissions=[FeaturePermission.create_as("premium")]) async def premium_feature(self): return {"feature": "premium"} # You can even combine injected permissions with operators @http_get('both/', permissions=[FeaturePermission.create_as("basic") & FeaturePermission.create_as("premium")]) async def both_features(self): return {"feature": "both"} ``` -------------------------------- ### Route Decorator Usage Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_route.md Demonstrates how to use the route decorator to define GET, POST, PUT, DELETE, and PATCH endpoints on a controller class. ```APIDOC ## GET /test ### Description Defines a GET endpoint at the specified path. ### Method GET ### Endpoint /test ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) - **message** (str) - A success message. #### Response Example { "message": "test" } ## POST /some/path ### Description Defines a POST endpoint at the specified path. ### Method POST ### Endpoint /some/path ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ## PUT /some/path ### Description Defines a PUT endpoint at the specified path. ### Method PUT ### Endpoint /some/path ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ## DELETE /some/path ### Description Defines a DELETE endpoint at the specified path. ### Method DELETE ### Endpoint /some/path ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ## PATCH /some/path ### Description Defines a PATCH endpoint at the specified path. ### Method PATCH ### Endpoint /some/path ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ## GENERIC /some/path (POST, PATCH) ### Description Defines a generic endpoint that accepts multiple HTTP methods. ### Method POST, PATCH ### Endpoint /some/path ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body None ### Request Example None ### Response #### Success Response (200) None #### Response Example None ``` -------------------------------- ### Pagination with Filtering using FilterSchema Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/pagination.md This example shows how to combine pagination with Django Ninja's `FilterSchema`. Filters are applied to the queryset before pagination occurs. The `BookFilterSchema` defines filterable fields for the book model. ```python from typing import Optional from ninja import FilterSchema from ninja_extra.pagination import paginate, PageNumberPaginationExtra, PaginatedResponseSchema from ninja_extra import api_controller, route, NinjaExtraAPI from ninja import ModelSchema from myapp.models import Book class BookSchema(ModelSchema): class Config: model = Book model_fields = ['id', 'title', 'author', 'price', 'published_date'] # Define a FilterSchema for your model class BookFilterSchema(FilterSchema): title: Optional[str] = None author: Optional[str] = None min_price: Optional[float] = None @api_controller('/books') class BookController: @route.get('', response=PaginatedResponseSchema[BookSchema]) @paginate(PageNumberPaginationExtra, filter_schema=BookFilterSchema, page_size=20) def list_books(self): return Book.objects.all() api = NinjaExtraAPI(title='Books API') api.register_controllers(BookController) ``` -------------------------------- ### Advanced Permissions with Custom Permission Classes Source: https://github.com/eadwincode/django-ninja-extra/blob/master/README.md Implement custom permission logic using PermissionBase and apply them at the controller or route level. This example shows IsAuthenticated and a custom IsAdmin permission. ```python from ninja_extra import api_controller, http_get from ninja_extra.permissions import IsAuthenticated, PermissionBase # Custom permission class IsAdmin(PermissionBase): def has_permission(self, context): return context.request.user.is_staff @api_controller('/admin', tags=['Admin'], permissions=[IsAuthenticated, IsAdmin]) class AdminController: @http_get('/stats') def get_stats(self): return {"status": "admin only data"} @http_get('/public', permissions=[]) # Override to make public def public_stats(self): return {"status": "public data"} ``` -------------------------------- ### List Events by Category using list Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Shows how to create a list endpoint using ModelEndpointFactory.list with a custom queryset_getter. This example filters events based on a provided category_id. ```python from ninja_extra import ( ModelConfig, ModelControllerBase, ModelSchemaConfig, api_controller, ModelEndpointFactory ) from .models import Event, Category @api_controller("/events") class EventModelController(ModelControllerBase): model_config = ModelConfig( model=Event, schema_config=ModelSchemaConfig(read_only_fields=["id", "category"]), ) get_events_by_category = ModelEndpointFactory.list( path="/category/{int:category_id}/", schema_out=model_config.retrieve_schema, lookup_param='category_id', queryset_getter=lambda self, **kw: Category.objects.filter(pk=kw['category_id']).first().events.all() ) ``` -------------------------------- ### Accessing Authenticated User via RouteContext Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/route_context.md A concise example demonstrating how to get the authenticated user object from `self.context.request.user` within a controller method. ```python @route.get("/profile") def get_profile(self): user = self.context.request.user return {"username": user.username} ``` -------------------------------- ### Basic GET Route Definition Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_route.md Defines a simple GET endpoint within an API controller class. ```python from ninja_extra import route, api_controller @api_controller class MyController: @route.get('/test') def test(self): return {'message': 'test'} ``` -------------------------------- ### Register API with Controllers Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/dependency-injection/index.md Initialize NinjaExtraAPI and register your controllers to make them available via the API. ```python from ninja_extra import NinjaExtraAPI api = NinjaExtraAPI() api.register_controllers(TodoController) ``` -------------------------------- ### Asynchronous GET Route Definition Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_route.md Defines an asynchronous GET endpoint within an API controller class, suitable for I/O-bound operations. ```python import asyncio from ninja_extra import http_get, api_controller @api_controller class MyController: @http_get("/say-after") async def say_after(self, delay: int, word: str): await asyncio.sleep(delay) return {'saying': word} ``` -------------------------------- ### Format Code Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/contribution.md Execute this command to automatically format your code according to the project's style guidelines. ```bash make fmt ``` -------------------------------- ### Get User by ID Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md Retrieves a specific user by their ID via a GET request. It accepts a user ID and returns the user object serialized as UserSchema. ```APIDOC ## GET /users/{user_id} ### Description Retrieves a specific user by their ID. ### Method GET ### Endpoint /users/{user_id} ### Parameters #### Path Parameters - **user_id** (int) - Required - The ID of the user to retrieve. ### Response #### Success Response (200) - (UserSchema) - The user object. ### Response Example ```json { "username": "testuser", "email": "test@example.com", "first_name": "Test" } ``` ``` -------------------------------- ### Create and Activate Virtual Environment (Linux/macOS) Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/contribution.md Use this command to create a Python virtual environment and activate it on Linux or macOS systems. ```bash python -m venv venv source venv/bin/activate # Linux/macOS ``` -------------------------------- ### Test Synchronous GET Request with TestClient Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/testing.md Use TestClient to simulate a GET request to a synchronous controller endpoint. Ensure the controller and test are set up correctly for Django database operations. ```python import pytest from .controllers import UserController from ninja_extra.testing import TestClient @pytest.mark.django_db class TestMyMathController: def test_get_users(self): client = TestClient(UserController) response = client.get('/users') assert response.status_code == 200 assert response.json()[0] == { 'first_name': 'Ninja Extra', 'username': 'django_ninja', 'email': 'john.doe@gmail.com' } ``` -------------------------------- ### Dependency Injection with Services Source: https://github.com/eadwincode/django-ninja-extra/blob/master/README.md Demonstrates how to use dependency injection with a custom service class (UserService) within a controller. ```python from injector import inject from ninja_extra import api_controller, http_get # Service class class UserService: def get_user_details(self, user_id: int): return {"user_id": user_id, "status": "active"} # Controller with dependency injection @api_controller('/users', tags=['Users']) class UserController: def __init__(self, user_service: UserService): self.user_service = user_service @http_get('/{user_id}') def get_user(self, user_id: int): return self.user_service.get_user_details(user_id) ``` -------------------------------- ### Basic Model Controller Configuration Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/02_model_configuration.md Demonstrates basic configuration of a Model Controller with common route information for create, list, and find one operations. ```python from ninja_extra import api_controller, ModelControllerBase, ModelConfig from .models import Event @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"], } ) ``` -------------------------------- ### Define Django Models Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/01_getting_started.md Example Django models for Category and Event. The Event model has a OneToOneField to Category. ```python from django.db import models class Category(models.Model): title = models.CharField(max_length=100) class Event(models.Model): title = models.CharField(max_length=100) category = models.OneToOneField( Category, null=True, blank=True, on_delete=models.SET_NULL, related_name='events' ) start_date = models.DateField() end_date = models.DateField() def __str__(self): return self.title ``` -------------------------------- ### Create and Activate Virtual Environment (Windows) Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/contribution.md Use this command to create a Python virtual environment and activate it on Windows systems. ```bash python -m venv venv .\venv\Scripts\activate # Windows ``` -------------------------------- ### Exact Email Search Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/searching.md This example shows how to perform an exact case-insensitive search on the 'email' field by prefixing it with '=' in `search_fields`. ```python @route.get('/iexact-email', response=List[UserSchema]) @searching(search_fields=['=email']) def get_users_with_search_iexact_email(self): return [u for u in user_model.objects.all()] ``` -------------------------------- ### IsAdminUser Permission Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Use IsAdminUser to restrict access to endpoints only for users with staff privileges. This is suitable for administrative functions. ```python from ninja_extra import permissions, api_controller, http_get @api_controller("/admin", permissions=[permissions.IsAdminUser]) class AdminController: @http_get("/stats") def get_stats(self): return {"active_users": 100, "total_posts": 500} ``` -------------------------------- ### Configure Service Injection in settings.py Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/03_model_service.md Set up the `NINJA_EXTRA` dictionary in your `settings.py` to specify the injector modules to be loaded. This enables features like automatic event notifications and user activity tracking. ```python NINJA_EXTRA = { 'INJECTOR_MODULES': [ 'your_app.injector_module.EventModule' ] } ``` -------------------------------- ### Object-Level Async Permission Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Implement object-level asynchronous permissions by defining the has_object_permission_async method. This example checks if the user is the owner of the object. ```python class IsOwnerAsync(AsyncBasePermission): async def has_object_permission_async(self, request, controller, obj): # Async check on the object return obj.owner_id == request.user.id ``` -------------------------------- ### Advanced Model Controller Configuration with Permissions and Throttling Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/02_model_configuration.md Illustrates advanced configuration including custom status codes, authentication, permissions, throttling, and OpenAPI extra configurations for create, update, and delete routes. ```python from ninja_extra import status from ninja_extra.permissions import IsAuthenticated, IsAdminUser from ninja_extra.throttling import AnonRateThrottle from ninja_extra import api_controller, ModelControllerBase, ModelConfig from .models import Event @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 Parameter Handling in Controllers Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/04_parameters.md Demonstrates how parameter handling works for asynchronous controllers. It uses `sync_to_async` to bridge synchronous database operations within an asynchronous service method. ```python from ninja_extra.sync_to_async import sync_to_async class AsyncCustomParamsModelService(ModelService): async def get_filtered_events(self, **kwargs): @sync_to_async def get_events(): queryset = self.model.objects.all() if kwargs.get('category'): queryset = queryset.filter(category_id=kwargs['category']) if kwargs.get('status'): queryset = queryset.filter(status=kwargs['status']) return queryset return await get_events() @api_controller("/events") class AsyncEventModelController(ModelControllerBase): service_type = AsyncCustomParamsModelService model_config = ModelConfig( model=Event, async_routes=True ) list_events = ModelEndpointFactory.list( path="/?category=int&status=str", schema_out=EventSchema, queryset_getter=lambda self, **kwargs: self.service.get_filtered_events(**kwargs) ) ``` -------------------------------- ### IsAuthenticatedOrReadOnly Permission Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Utilize IsAuthenticatedOrReadOnly for endpoints that should be readable by anyone but writable only by authenticated users. This is common for resource listing and creation endpoints. ```python from ninja_extra import permissions, api_controller, http_get, http_post @api_controller("/posts", permissions=[permissions.IsAuthenticatedOrReadOnly]) class BlogController: @http_get("/") # Accessible to everyone def list_posts(self): return {"posts": ["Post 1", "Post 2"]} @http_post("/") # Only accessible to authenticated users def create_post(self, request, title: str): return {"message": f"Post '{title}' created by {request.user.username}"} ``` -------------------------------- ### Basic Path Parameters Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/04_parameters.md Demonstrates how to define a basic path parameter for looking up an event by its ID. ```APIDOC ## GET /events/{int:id} ### Description Retrieves a specific event using its ID from the URL path. ### Method GET ### Endpoint /events/{int:id} ### Parameters #### Path Parameters - **id** (int) - Required - The unique identifier for the event. ### Response #### Success Response (200) - **EventSchema** - The schema representing the event object. ``` -------------------------------- ### IsAuthenticated Permission Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Employ IsAuthenticated to restrict access to only authenticated users. Ensure users are logged in before accessing endpoints decorated with this permission. ```python from ninja_extra import permissions, api_controller, http_get @api_controller(permissions=[permissions.IsAuthenticated]) class PrivateController: @http_get("/profile") def get_profile(self, request): return { "username": request.user.username, "email": request.user.email } ``` -------------------------------- ### Generated Event Schemas Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/01_getting_started.md Example of auto-generated Pydantic schemas for creating/updating and retrieving Event data. These handle input validation and output serialization. ```python # Auto-generated create/update schema class EventCreateSchema(Schema): title: str start_date: date end_date: date category: Optional[int] = None # Auto-generated retrieve schema class EventSchema(Schema): id: int title: str start_date: date end_date: date category: Optional[int] = None ``` -------------------------------- ### Register Services with Scopes Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/dependency-injection/index.md Register services with 'singleton' or 'noscope' (transient) scopes. 'singleton' is best for stateless services or those maintaining application-wide state, while 'noscope' is for services needing a new instance per request. ```python from injector import Module, singleton, noscope, Binder class TodoModule(Module): def configure(self, binder: Binder) -> None: # Singleton scope - same instance for entire application # TodoRepository maintains application state (the todos list) binder.bind(TodoRepository, to=TodoRepository, scope=singleton) # Singleton scope - stateless service that only contains business logic binder.bind(TodoService, to=TodoService, scope=singleton) # Example of when to use noscope # binder.bind(RequestContextService, to=RequestContextService, scope=noscope) ``` -------------------------------- ### Basic ControllerBase Usage Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md Demonstrates the basic structure of a controller by inheriting from ControllerBase and applying the api_controller decorator. ```python from ninja_extra import ControllerBase, api_controller @api_controller('/users') class UserControllerBase(ControllerBase): ... ``` -------------------------------- ### Custom Async Permission Example Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Demonstrates how to create a custom asynchronous permission class `IsStaffOrOwnerAsync` that checks if a user is authenticated, staff, or the owner of an object. ```APIDOC ## Custom async permission class IsStaffOrOwnerAsync(AsyncBasePermission): async def has_permission_async(self, request, controller): return request.user.is_authenticated async def has_object_permission_async(self, request, controller, obj): # Either the user is staff or owns the object return request.user.is_staff or obj.owner_id == request.user.id ``` -------------------------------- ### Define API Version 1 Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/versioning.md Create a NinjaExtraAPI instance for version 1.0.0 and register controllers. This serves as the base for versioned APIs. ```Python from ninja_extra import NinjaExtraAPI, route, api_controller @api_controller class MyV1Controller: @route.get('/hello') def hello(self): return {'message': 'Hello from V1'} @route.get('/example') def example(self): return {'message': 'Hello from V1 Example'} api = NinjaExtraAPI(version='1.0.0') api.register_controllers(MyV1Controller) ``` -------------------------------- ### FilterSchema with Model Controllers Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/pagination.md Integrate FilterSchema with Model Controllers using ModelPagination for automatic filtering and pagination. This simplifies the setup for common CRUD operations. ```python from ninja import FilterSchema from ninja_extra.controllers import ModelControllerBase from ninja_extra.controllers.model import ModelConfig, ModelPagination from ninja_extra.pagination import PageNumberPaginationExtra from myapp.models import Book class BookFilterSchema(FilterSchema): title: Optional[str] = None author__name: Optional[str] = None price__gte: Optional[float] = None class BookModelController(ModelControllerBase): model_config = ModelConfig( model=Book, pagination=ModelPagination( klass=PageNumberPaginationExtra, filter_schema=BookFilterSchema, paginator_kwargs={"page_size": 25} ) ) ``` -------------------------------- ### Define APIs with Different Authentication and Namespaces Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/versioning.md Instantiate NinjaExtraAPI with different authentication methods and URL namespaces to separate distinct API functionalities. Ensure unique versions or namespaces for each instance. ```Python from ninja_extra import NinjaExtraAPI api = NinjaExtraAPI(auth=token_auth, urls_namespace='public_api') api_private = NinjaExtraAPI(auth=session_auth, urls_namespace='private_api') urlpatterns = [ path('api/', api.urls), path('internal-api/', api_private.urls), ] ``` -------------------------------- ### Async Model Endpoint Factory Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Demonstrates using ModelAsyncEndpointFactory for creating asynchronous custom endpoints. This example mirrors the synchronous version but uses async handlers. ```APIDOC ## Async Model Endpoint Factory ### Description The `ModelAsyncEndpointFactory` provides the same API as `ModelEndpointFactory` but is designed for generating asynchronous endpoints. This allows for non-blocking operations within your API. ### Example: Asynchronous Addition of Event to New Category ```python from typing import Any from pydantic import BaseModel from ninja_extra import ( ModelConfig, ModelControllerBase, ModelSchemaConfig, api_controller, ModelAsyncEndpointFactory ) from .models import Event, Category class CreateCategorySchema(BaseModel): title: str class CategorySchema(BaseModel): id: str title: str @api_controller("/events") class EventModelController(ModelControllerBase): model_config = ModelConfig( model=Event, schema_config=ModelSchemaConfig(read_only_fields=["id", "category"]), ) add_event_to_new_category = ModelAsyncEndpointFactory.create( path="/{int:event_id}/new-category", schema_in=CreateCategorySchema, schema_out=CategorySchema, custom_handler=lambda self, data, **kw: self.handle_add_event_to_new_category(data, **kw) ) async def handle_add_event_to_new_category( self, data: CreateCategorySchema, event_id: int, **kw: Any ) -> Category: event = await self.service.get_one_async(pk=event_id) category = Category.objects.create(title=data.title) event.category = category event.save() return category ``` This example defines an asynchronous endpoint `POST /{int:event_id}/new-category`. The `handle_add_event_to_new_category` method is now an `async` function, and it uses `await` for asynchronous operations like fetching the event (`get_one_async`). ``` -------------------------------- ### Customize Model Controller Routes Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/01_getting_started.md Limit the generated routes for a Model Controller using the 'allowed_routes' parameter in ModelConfig. This example only generates list and find_one endpoints. ```python @api_controller("/events") class EventModelController(ModelControllerBase): model_config = ModelConfig( model=Event, allowed_routes=["list", "find_one"] # Only generate GET and GET/{id} endpoints ) ``` -------------------------------- ### Define Route with Path Parameter Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/tutorial/path.md Declare a GET route with a path parameter 'user_id' of type integer. The parameter value is passed directly to the controller method. ```python from ninja_extra import api_controller, route from ninja import constants @api_controller('', tags=['My Operations'], auth=constants.NOT_SET, permissions=[]) class MyAPIController: @route.get('/users/{user_id}') def get_user_by_id(self, user_id: int): return {'user_id': user_id} ``` -------------------------------- ### Combining Permissions Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Demonstrates how to combine multiple permissions using logical operators like AND (&), OR (|), and NOT (~). This allows for fine-grained access control based on various conditions. ```APIDOC ## GET /content/basic ### Description Allows access if the user is authenticated OR has a premium subscription. ### Method GET ### Endpoint /content/basic ### Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The basic content accessible to the user. #### Response Example ```json { "content": "Basic content" } ``` ## GET /content/premium ### Description Allows access only if the user is authenticated AND has a premium subscription. ### Method GET ### Endpoint /content/premium ### Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The premium content accessible to the user. #### Response Example ```json { "content": "Premium content" } ``` ## GET /content/non-premium ### Description Allows access only if the user is authenticated AND does NOT have a premium subscription. ### Method GET ### Endpoint /content/non-premium ### Parameters None ### Request Example None ### Response #### Success Response (200) - **content** (string) - The content accessible to non-premium users. #### Response Example ```json { "content": "Content for non-premium users" } ``` ``` -------------------------------- ### Configuration Inheritance for Model Controllers Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller/02_model_configuration.md Demonstrates how ModelConfig supports inheritance. A base configuration class can be defined and then extended or overridden in specific controllers. ```python from ninja_extra.controllers import ModelConfig, ModelSchemaConfig, api_controller, ModelControllerBase from .models import Event 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"] ) ``` -------------------------------- ### Combine Permissions with AND, OR, NOT Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_permission.md Demonstrates combining Django Ninja Extra permissions using logical AND (&), OR (|), and NOT (~) operators. Ensure the necessary permission classes are imported. ```python from ninja_extra import permissions, api_controller, http_get class HasPremiumSubscription(permissions.BasePermission): def has_permission(self, request, controller): return request.user.has_perm('premium_subscription') @api_controller("/content") class ContentController: @http_get("/basic", permissions=[permissions.IsAuthenticated | HasPremiumSubscription()]) def basic_content(self): return {"content": "Basic content"} @http_get("/premium", permissions=[permissions.IsAuthenticated & HasPremiumSubscription()]) def premium_content(self): return {"content": "Premium content"} @http_get("/non-premium", permissions=[permissions.IsAuthenticated & ~HasPremiumSubscription()]) def non_premium_content(self): return {"content": "Content for non-premium users"} ``` -------------------------------- ### Get Event Category Endpoint Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Demonstrates how to use ModelEndpointFactory.find_one to create an endpoint that retrieves the category of a specific event. It utilizes an object_getter callback to fetch the related category. ```APIDOC ## GET /events/{int:event_id}/category ### Description Retrieves the category associated with a specific event. ### Method GET ### Endpoint /events/{int:event_id}/category ### Parameters #### Path Parameters - **event_id** (int) - Required - The ID of the event to retrieve the category for. ### Request Example (No request body for GET request) ### Response #### Success Response (200) - **(Schema defined by CategorySchema)** - Description of the category object returned. #### Response Example (Example response based on CategorySchema) ``` -------------------------------- ### Create a Basic Async Permission Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/api_controller_async_permission.md Inherit from AsyncBasePermission and implement has_permission_async. This method can perform async database operations. ```python from ninja_extra.permissions import AsyncBasePermission class IsUserPremiumAsync(AsyncBasePermission): async def has_permission_async(self, request, controller): # You can perform async database operations here user = request.user # Async check (example using Django's async ORM methods) subscription = await user.subscription.aget() return subscription and subscription.is_premium # The sync version is automatically handled for you # through async_to_sync conversion ``` -------------------------------- ### Get Event Category using find_one Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/model_controller.md Demonstrates retrieving a related model object using ModelEndpointFactory.find_one with a custom object_getter. The lookup_param specifies the primary key source. ```python from ninja_extra import ( ModelConfig, ModelControllerBase, ModelSchemaConfig, api_controller, ModelEndpointFactory ) from .models import Event, Category @api_controller("/events") class EventModelController(ModelControllerBase): model_config = ModelConfig( model=Event, schema_config=ModelSchemaConfig(read_only_fields=["id", "category"]), ) get_event_category = ModelEndpointFactory.find_one( path="/{int:event_id}/category", schema_out=CategorySchema, lookup_param='event_id', object_getter=lambda self, pk, **kw: self.service.get_one(pk=pk).category ) ``` -------------------------------- ### List Users Source: https://github.com/eadwincode/django-ninja-extra/blob/master/docs/api_controller/index.md Retrieves a paginated list of users via a GET request. It supports pagination with a page size of 50 and returns a PaginatedResponseSchema containing UserSchema objects. ```APIDOC ## GET /users ### Description Retrieves a paginated list of all users. ### Method GET ### Endpoint /users ### Query Parameters - **page** (int) - Optional - The page number to retrieve. - **page_size** (int) - Optional - The number of items per page (defaults to 50). ### Response #### Success Response (200) - (pagination.PaginatedResponseSchema[UserSchema]) - A paginated response containing a list of users. ### Response Example ```json { "count": 100, "next": "/api/users?page=2&page_size=50", "previous": null, "results": [ { "username": "user1", "email": "user1@example.com", "first_name": "User One" }, { "username": "user2", "email": "user2@example.com", "first_name": "User Two" } ] } ``` ```