django-dev-ninja

Django Ninja API Development

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "django-dev-ninja" with this command: npx skills add sergio-bershadsky/ai/sergio-bershadsky-ai-django-dev-ninja

Django Ninja API Development

Opinionated Django Ninja patterns with single-endpoint-per-file organization.

Core Principles

  • One endpoint = one file - Each endpoint lives in its own file

  • Logical grouping - Endpoints grouped in subpackages by domain

  • Router per group - Each group has its own router

  • Schemas in separate package - Pydantic models in schemas/

  • Services for logic - Business logic in services, not endpoints

API Structure

myapp/ ├── api/ │ ├── init.py # Main NinjaAPI instance │ ├── users/ │ │ ├── init.py # Router: users_router │ │ ├── list.py # GET /users/ │ │ ├── detail.py # GET /users/{id} │ │ ├── create.py # POST /users/ │ │ ├── update.py # PUT /users/{id} │ │ └── delete.py # DELETE /users/{id} │ ├── products/ │ │ ├── init.py │ │ ├── list.py │ │ ├── detail.py │ │ └── search.py │ └── auth/ │ ├── init.py │ ├── login.py │ ├── logout.py │ └── refresh.py └── schemas/ ├── init.py ├── user.py # UserIn, UserOut, UserPatch ├── product.py └── common.py # Pagination, errors

Main API Setup

In api/init.py :

from ninja import NinjaAPI from ninja.security import HttpBearer

from .users import router as users_router from .products import router as products_router from .auth import router as auth_router

class AuthBearer(HttpBearer): def authenticate(self, request, token): # Token validation logic from ..services.auth import AuthService return AuthService.validate_token(token)

api = NinjaAPI( title="My API", version="1.0.0", description="API documentation", auth=AuthBearer(), )

Register routers

api.add_router("/users", users_router, tags=["Users"]) api.add_router("/products", products_router, tags=["Products"]) api.add_router("/auth", auth_router, tags=["Authentication"], auth=None)

Router Setup

Each group has a router in init.py :

api/users/init.py

from ninja import Router

from .list import router as list_router from .detail import router as detail_router from .create import router as create_router from .update import router as update_router from .delete import router as delete_router

router = Router()

Merge endpoint routers

router.add_router("", list_router) router.add_router("", detail_router) router.add_router("", create_router) router.add_router("", update_router) router.add_router("", delete_router)

Endpoint File Template

Each endpoint in its own file:

api/users/create.py

from ninja import Router from django.http import HttpRequest

from ...schemas.user import UserIn, UserOut from ...services.user import UserService

router = Router()

@router.post("/", response={201: UserOut}) def create_user(request: HttpRequest, payload: UserIn) -> UserOut: """Create a new user.""" user = UserService.create(payload) return user

Schema Organization

Pydantic schemas in schemas/ package:

schemas/user.py

from uuid import UUID from datetime import datetime from pydantic import BaseModel, EmailStr, Field

class UserBase(BaseModel): """Shared user fields.""" email: EmailStr name: str = Field(max_length=255)

class UserIn(UserBase): """Input schema for creating users.""" password: str = Field(min_length=8)

class UserPatch(BaseModel): """Partial update schema.""" email: EmailStr | None = None name: str | None = Field(None, max_length=255)

class UserOut(UserBase): """Output schema for users.""" id: UUID is_active: bool created_at: datetime

class Config:
    from_attributes = True

Common Patterns

Pagination

schemas/common.py

from typing import Generic, TypeVar, List from pydantic import BaseModel

T = TypeVar("T")

class PaginatedResponse(BaseModel, Generic[T]): items: List[T] total: int page: int per_page: int pages: int

api/users/list.py

from ninja import Router, Query from ...schemas.user import UserOut from ...schemas.common import PaginatedResponse

router = Router()

@router.get("/", response=PaginatedResponse[UserOut]) def list_users( request, page: int = Query(1, ge=1), per_page: int = Query(20, ge=1, le=100), ): """List users with pagination.""" from ...services.user import UserService return UserService.list_paginated(page, per_page)

Error Handling

schemas/common.py

class ErrorResponse(BaseModel): detail: str code: str | None = None

class ValidationErrorResponse(BaseModel): detail: list[dict]

api/users/detail.py

from ninja import Router from django.http import Http404 from ...schemas.user import UserOut from ...schemas.common import ErrorResponse

router = Router()

@router.get("/{user_id}", response={200: UserOut, 404: ErrorResponse}) def get_user(request, user_id: UUID): """Get user by ID.""" from ...services.user import UserService

user = UserService.get_by_id(user_id)
if not user:
    return 404, {"detail": "User not found", "code": "USER_NOT_FOUND"}
return user

File Upload

api/files/upload.py

from ninja import Router, File, UploadedFile from ...schemas.file import FileOut

router = Router()

@router.post("/upload", response=FileOut) def upload_file(request, file: UploadedFile = File(...)): """Upload a file.""" from ...services.file import FileService return FileService.save(file)

URL Configuration

Register API in urls.py :

config/urls.py

from django.urls import path from apps.myapp.api import api

urlpatterns = [ path("api/", api.urls), ]

Authentication Patterns

See references/endpoints.md for detailed authentication patterns including:

  • JWT authentication

  • API key authentication

  • Session authentication

  • Permission decorators

Additional Resources

Reference Files

  • references/endpoints.md

  • Detailed endpoint patterns, authentication, permissions

  • references/routers.md

  • Router organization, versioning, OpenAPI customization

Related Skills

  • django-dev - Core Django patterns and model organization

  • django-dev-test - Testing API endpoints with pytest

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

django-dev-unfold

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

django-dev

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

django-dev-test

No summary provided by upstream source.

Repository SourceNeeds Review
General

frappe-doctype

No summary provided by upstream source.

Repository SourceNeeds Review