文章列表
4 分钟阅读

Django REST Framework 入门:把 Django 做成 API


系列:Python Web 框架

第 8 / 11 篇

  1. FastAPI 安装与使用指南
  2. FastAPI 进阶使用指南
  3. Django 安装与使用指南
  4. Django 进阶使用指南
  5. Django 与 FastAPI 对比:如何选择合适的 Python Web 框架
  6. Python Web 框架有哪些,怎么选
  7. Flask 安装与使用指南
  8. Django REST Framework 入门:把 Django 做成 API
  9. FastAPI 项目实战:用户登录与 JWT 鉴权
  10. Python Web 项目部署指南:Gunicorn、Uvicorn、Nginx 和 Docker
  11. Python Web 项目结构怎么设计

Django 本身是全栈框架,模板、表单、后台管理都很强。但很多项目后来会走向前后端分离:前端用 Vue、React 或小程序,后端只提供 JSON API。

这时候常用的方案就是 Django REST Framework,简称 DRF。

它不是 Django 的一个小插件,而是一整套 API 开发工具:序列化器、视图、路由、权限、认证、分页、过滤、可浏览 API 页面都给你准备好了。你可以理解为:Django 负责数据库、模型、配置和生态,DRF 负责把它们变成 API。

这篇默认你已经看过 Django 安装与使用指南,至少知道 project、app、model、migration 是什么。

安装和准备项目

在已有 Django 项目里安装:

Terminal window
pip install djangorestframework

rest_framework 加进 INSTALLED_APPS

INSTALLED_APPS = [
"django.contrib.admin",
"django.contrib.auth",
"django.contrib.contenttypes",
"django.contrib.sessions",
"django.contrib.messages",
"django.contrib.staticfiles",
"rest_framework",
"blog",
]

下面用一个最普通的文章模型做例子。

blog/models.py

from django.db import models
class Article(models.Model):
title = models.CharField(max_length=120)
slug = models.SlugField(unique=True)
body = models.TextField()
published = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title

迁移:

Terminal window
python manage.py makemigrations
python manage.py migrate

Serializer:把模型变成 JSON

DRF 里最核心的概念是 Serializer。它负责两件事:

  1. 把 Django model 转成 JSON;
  2. 把请求里的 JSON 校验后转成 Python 数据。

创建 blog/serializers.py

from rest_framework import serializers
from .models import Article
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ["id", "title", "slug", "body", "published", "created_at"]
read_only_fields = ["id", "created_at"]

这段代码看起来像 Django Form,但它面向 API。read_only_fields 的意思是客户端不能传这些字段来改。

如果你不想暴露完整正文,也可以拆两个 Serializer:

class ArticleListSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ["id", "title", "slug", "published", "created_at"]

列表页用轻量字段,详情页再返回正文,这是实际项目里很常见的优化。

ViewSet:少写重复 CRUD

DRF 可以用函数视图、类视图,也可以用 ViewSet。入门阶段建议先用 ViewSet,它能少写很多重复代码。

blog/views.py

from rest_framework import viewsets
from .models import Article
from .serializers import ArticleSerializer
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all().order_by("-created_at")
serializer_class = ArticleSerializer

这几行代码已经有了完整 CRUD:

GET /api/articles/ 列表
POST /api/articles/ 创建
GET /api/articles/1/ 详情
PUT /api/articles/1/ 全量更新
PATCH /api/articles/1/ 部分更新
DELETE /api/articles/1/ 删除

这就是 DRF 的生产力来源。

Router:自动生成 URL

mysite/urls.py

from django.contrib import admin
from django.urls import include, path
from rest_framework.routers import DefaultRouter
from blog.views import ArticleViewSet
router = DefaultRouter()
router.register("articles", ArticleViewSet, basename="article")
urlpatterns = [
path("admin/", admin.site.urls),
path("api/", include(router.urls)),
]

启动:

Terminal window
python manage.py runserver

打开 http://127.0.0.1:8000/api/articles/,你会看到 DRF 自带的可浏览 API 页面。它不是给最终用户用的,但开发调试很方便。

权限:不要默认全部开放

上面的 ModelViewSet 默认比较宽松。真实项目里至少要先限制写操作。

最简单的规则:游客可以看,登录用户才能改。

from rest_framework.permissions import IsAuthenticatedOrReadOnly
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all().order_by("-created_at")
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]

如果要全站默认配置:

REST_FRAMEWORK = {
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly",
],
}

我更建议在项目早期就写清权限,不要等 API 做完了再补。权限后补很容易漏。

分页和过滤

列表接口不分页是一个常见坑。数据少时没感觉,数据一多接口会突然变慢。

settings.py

REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}

简单搜索可以先手写:

class ArticleViewSet(viewsets.ModelViewSet):
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def get_queryset(self):
queryset = Article.objects.all().order_by("-created_at")
keyword = self.request.query_params.get("q")
if keyword:
queryset = queryset.filter(title__icontains=keyword)
return queryset

如果过滤条件很多,再考虑 django-filter。不要为了两个查询参数一上来就引入一堆抽象。

常见问题

Serializer 和 ModelForm 有什么区别

ModelForm 面向 HTML 表单,Serializer 面向 API 数据。它们都做校验,但输出目标不同。

如果你在做前后端分离接口,用 Serializer;如果你在做 Django 模板页面,用 Form 或 ModelForm。

ViewSet 会不会太魔法

会有一点。它把 CRUD 约定都封装起来了,所以入门很舒服,但出了复杂需求要知道怎么覆盖。

常见覆盖点:

def get_queryset(self):
...
def get_serializer_class(self):
...
def perform_create(self, serializer):
serializer.save(author=self.request.user)

项目复杂后,不要把业务全塞进 ViewSet。ViewSet 负责 HTTP 层,真正的业务逻辑可以放到 service 函数里。

DRF 和 FastAPI 怎么选

如果你已经在 Django 生态里,需要 admin、ORM、权限和成熟插件,DRF 很合适。

如果你是从零写一个纯 API 服务,而且非常依赖类型提示和 OpenAPI 文档,FastAPI 安装与使用指南 会更轻。

更完整的取舍可以看 Django 与 FastAPI 对比:如何选择合适的 Python Web 框架

API 文档怎么办

DRF 自带可浏览 API,但不是正式的 OpenAPI 文档体验。生产项目常见选择是 drf-spectacular:

Terminal window
pip install drf-spectacular

然后按 drf-spectacular 文档 配置 schema 和 Swagger UI。

总结

DRF 的价值是把 Django 的成熟生态接到 API 开发上。

最小可用路径是:

Model 定义数据
Serializer 做输入输出转换
ViewSet 处理 CRUD
Router 生成 URL
Permission 限制访问
Pagination 保护列表接口

如果你已经有 Django 项目,DRF 是很自然的下一步;如果你从零开始做纯 API,要认真比较一下 FastAPI。Django + DRF 的优势是稳和完整,代价是写法更重。更多细节可以看 Django REST Framework 官方文档