Django + Ninja API 实战:构建高性能RESTful服务的最佳实践

By | 2026年6月28日

为什么选择Django Ninja?

Django Ninja 是一个基于 Python 类型提示的 Django REST 框架,它结合了 Django 的成熟生态和 FastAPI 的简洁高效。相比于 Django REST Framework (DRF),Ninja 具有以下优势:

  • 自动生成 OpenAPI 文档:无需额外配置,即得 Swagger UI 和 ReDoc。
  • 类型安全:利用 Pydantic 进行参数校验,减少运行时错误。
  • 高性能:基于异步视图,支持高并发场景。
  • 轻量级:API 代码更简洁,学习成本低。

本文将带你从零搭建一个图书管理 API 系统,涵盖常见业务场景。

环境准备

确保已安装 Python 3.8+,然后创建虚拟环境并安装依赖:


pip install django ninja

第一步:创建 Django 项目


django-admin startproject bookmanager
cd bookmanager
python manage.py startapp books

books 添加到 INSTALLED_APPS


# bookmanager/settings.py
INSTALLED_APPS = [
    ...
    'books',
]

第二步:定义模型


# books/models.py
from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=200)
    author = models.CharField(max_length=100)
    published_date = models.DateField()
    isbn = models.CharField(max_length=13, unique=True)
    price = models.DecimalField(max_digits=6, decimal_places=2)

    def __str__(self):
        return self.title

执行迁移:


python manage.py makemigrations
python manage.py migrate

第三步:创建 Ninja API

books 目录下创建 api.py


# books/api.py
from ninja import NinjaAPI, ModelSchema, Schema
from typing import List
from .models import Book
from django.shortcuts import get_object_or_404

api = NinjaAPI()

# 定义输入输出 Schema
class BookIn(Schema):
    title: str
    author: str
    published_date: str  # 接收字符串,后续转换
    isbn: str
    price: float

class BookOut(ModelSchema):
    class Meta:
        model = Book
        fields = ['id', 'title', 'author', 'published_date', 'isbn', 'price']

# 转换日期字符串
from datetime import datetime

@api.post("/books/", response=BookOut)
def create_book(request, payload: BookIn):
    # 将字符串日期转换为 date 对象
    try:
        published_date = datetime.strptime(payload.published_date, "%Y-%m-%d").date()
    except ValueError:
        return api.create_response(request, {"error": "日期格式错误,应为 YYYY-MM-DD"}, status=400)
    book = Book.objects.create(
        title=payload.title,
        author=payload.author,
        published_date=published_date,
        isbn=payload.isbn,
        price=payload.price
    )
    return book

@api.get("/books/", response=List[BookOut])
def list_books(request):
    return Book.objects.all()

@api.get("/books/{book_id}", response=BookOut)
def get_book(request, book_id: int):
    book = get_object_or_404(Book, id=book_id)
    return book

@api.put("/books/{book_id}", response=BookOut)
def update_book(request, book_id: int, payload: BookIn):
    book = get_object_or_404(Book, id=book_id)
    try:
        published_date = datetime.strptime(payload.published_date, "%Y-%m-%d").date()
    except ValueError:
        return api.create_response(request, {"error": "日期格式错误"}, status=400)
    book.title = payload.title
    book.author = payload.author
    book.published_date = published_date
    book.isbn = payload.isbn
    book.price = payload.price
    book.save()
    return book

@api.delete("/books/{book_id}", response={204: None})
def delete_book(request, book_id: int):
    book = get_object_or_404(Book, id=book_id)
    book.delete()
    return 204, None

第四步:注册 API 路由

bookmanager/urls.py 中:


from django.contrib import admin
from django.urls import path
from books.api import api

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', api.urls),
]

第五步:运行并测试


python manage.py runserver

访问 http://127.0.0.1:8000/api/docs 即可看到 Swagger 文档。

测试 API

使用 curl 或 Postman 测试:


# 创建图书
curl -X POST http://127.0.0.1:8000/api/books/ \
  -H "Content-Type: application/json" \
  -d '{"title":"Django Ninja实战","author":"张三","published_date":"2024-01-15","isbn":"9781234567890","price":39.99}'

# 获取列表
curl http://127.0.0.1:8000/api/books/

进阶技巧:ORM 优化与分页

当数据量大时,直接返回 Book.objects.all() 可能导致性能问题。Ninja 内置了分页支持:


from ninja.pagination import paginate, PageNumberPagination

@api.get("/books/", response=List[BookOut])
@paginate(PageNumberPagination, page_size=10)
def list_books(request):
    return Book.objects.all().select_related()  # 优化关联查询

同时,在查询中使用 selectrelatedprefetchrelated 减少数据库查询次数。

错误处理最佳实践

使用 Ninja 的异常处理机制统一返回格式:


from ninja.errors import HttpError

@api.exception_handler(HttpError)
def custom_http_error_handler(request, exc):
    return api.create_response(
        request,
        {"detail": exc.message},
        status=exc.status_code,
    )

总结

本文介绍了如何使用 Django Ninja 快速构建一个图书管理 API,涵盖模型定义、Schema 设计、CRUD 操作、自动文档生成以及性能优化。相比于 DRF,Ninja 的代码量更少,类型安全更强,非常适合现代 API 开发。

下一步方向

  • 集成认证(JWT 或 Session)
  • 添加单元测试
  • 使用异步视图处理 I/O 密集型任务

欢迎在评论区交流你的实战经验!