快速入门 Django REST Framework (DRF):构建你的第一个 RESTful API
引言
随着移动应用、单页应用 (SPA) 和前后端分离架构的日益普及,构建强大的后端 API 变得至关重要。Django 是一个功能强大的 Python Web 框架,以其“电池包含”的哲学而闻名。然而,Django 本身更侧重于构建传统的、基于服务器渲染的 Web 应用。当需要构建为客户端提供数据的 RESTful API 时,Django REST Framework (DRF) 应运而生。
DRF 是一个灵活且功能强大的工具包,用于构建 Web API。它建立在 Django 的基础之上,提供了大量开箱即用的功能,极大地简化了 API 的开发过程。无论是序列化数据、处理请求、实现身份验证和权限控制,还是自动生成文档,DRF 都能为你提供强大的支持。
本篇文章旨在帮助完全的新手快速掌握 DRF 的核心概念,并通过一个简单的实际例子,带领你从零开始构建一个基本的 RESTful API。我们将涵盖环境搭建、核心组件(序列化器、视图、路由器)的使用,以及如何通过 DRF 的优秀特性——可浏览 API——进行测试。
学完本文,你将能够:
- 理解什么是 RESTful API 以及 DRF 的作用。
- 搭建 DRF 开发环境。
- 创建 Django 模型。
- 使用 DRF 的序列化器转换数据。
- 利用 DRF 的通用视图和视图集快速实现常见的 API 操作。
- 使用路由器简化 URL 配置。
- 通过可浏览 API 测试你的接口。
让我们开始吧!
前提条件
在深入 DRF 之前,你需要具备以下基础知识:
- Python 基础: 熟悉 Python 语法、数据结构和面向对象编程。
- Django 基础: 了解 Django 的项目结构、应用 (
app
) 的概念、模型 (models.py
) 的定义和使用、以及 URL 配置 (urls.py
)。你不需要是 Django 专家,但至少要知道如何创建一个项目和应用,并定义简单的模型。 - 虚拟环境: 强烈建议使用虚拟环境来隔离项目依赖。
- RESTful API 概念: 对 REST 架构风格有基本了解,知道资源 (Resources)、URI、HTTP 方法(GET, POST, PUT, PATCH, DELETE)以及状态码的含义。
如果你对上述某些概念不熟悉,建议先花一些时间学习 Django 的官方教程和 RESTful 相关的基础知识。
第一步:环境搭建与项目设置
首先,我们需要创建一个新的 Django 项目并安装 DRF。
-
创建虚拟环境 (推荐)
打开你的终端或命令行工具,导航到你希望存放项目的目录。然后创建并激活一个虚拟环境:
“`bash
python -m venv venvWindows
venv\Scripts\activate
macOS/Linux
source venv/bin/activate
“` -
安装 Django 和 DRF
在虚拟环境激活的状态下,使用 pip 安装所需的库:
bash
pip install django djangorestframework -
创建 Django 项目
现在,创建一个新的 Django 项目。我们将其命名为
myapiproject
。bash
django-admin startproject myapiproject .注意末尾的点(
.
)表示在当前目录下创建项目文件。 -
创建 Django 应用
在项目目录下,创建一个新的 Django 应用。我们将创建一个简单的 ToDo 列表 API,所以应用可以命名为
todoapi
。bash
python manage.py startapp todoapi -
注册应用
编辑
myapiproject/settings.py
文件,将todoapi
和rest_framework
添加到INSTALLED_APPS
列表中:“`python
myapiproject/settings.py
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,'rest_framework', # 添加 DRF 'todoapi', # 添加你的应用
]
… 其他设置 …
“`
-
运行数据库迁移
应用注册后,运行数据库迁移以创建 DRF 和 Django 自带的功能所需的表:
bash
python manage.py migrate
至此,你的 DRF 开发环境已经搭建完毕,并且项目也已基本配置完成。
第二步:定义数据模型 (Models)
接下来,我们需要定义 API 将要操作的数据模型。在 todoapi/models.py
中,我们将创建一个简单的 TodoItem
模型来表示待办事项。
“`python
todoapi/models.py
from django.db import models
class TodoItem(models.Model):
title = models.CharField(max_length=100)
description = models.TextField(blank=True, null=True)
completed = models.BooleanField(default=False)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
“`
这个模型非常简单:
* title
: 待办事项的标题(字符串)。
* description
: 待办事项的详细描述(可选文本)。
* completed
: 表示事项是否已完成(布尔值,默认为 False
)。
* created_at
: 事项创建的时间(自动设置为创建时的时间)。
定义好模型后,需要生成并应用数据库迁移:
bash
python manage.py makemigrations
python manage.py migrate
现在,数据库中已经有了 TodoItem
模型对应的表。
第三步:使用序列化器 (Serializers)
序列化器是 DRF 的核心组件之一,它承担着两个主要职责:
- 序列化: 将复杂的 Python 对象(如 Django 模型实例或查询集)转换为可以轻松渲染成 JSON、XML 或其他格式的简单数据类型(如 Python 字典、列表)。
- 反序列化: 将接收到的简单数据类型(通常是解析 JSON 或 XML 后的数据)转换回复杂的 Python 对象,同时执行数据验证。
对于大多数使用 Django 模型的情况,ModelSerializer
是最方便的选择,因为它会自动根据模型的字段生成相应的序列化器字段。
在 todoapi
应用目录下创建一个新文件 serializers.py
:
“`python
todoapi/serializers.py
from rest_framework import serializers
from .models import TodoItem
class TodoItemSerializer(serializers.ModelSerializer):
class Meta:
model = TodoItem
fields = ‘all‘ # 或者指定你想包含的字段,例如: fields = [‘id’, ‘title’, ‘completed’]
“`
这里我们创建了一个名为 TodoItemSerializer
的类,它继承自 serializers.ModelSerializer
。在内部的 Meta
类中,我们指定了:
* model = TodoItem
: 这个序列化器关联到 TodoItem
模型。
* fields = '__all__'
: 表示序列化器将包含模型中的所有字段。你也可以显式地列出需要包含的字段,例如 fields = ['id', 'title', 'completed']
,甚至可以使用 exclude
来排除特定字段。包含 'id'
字段通常是必要的,因为它代表了资源的唯一标识符。
这个简单的序列化器已经可以完成 TodoItem
模型实例和 Python 字典之间的互相转换以及基本的字段验证。
第四步:创建视图 (Views)
视图在 DRF 中负责处理请求和返回响应。与 Django 的视图类似,DRF 的视图可以是基于函数的 (api_view
装饰器) 或基于类的。在构建 API 时,基于类的视图 (CBVs) 通常更受欢迎,因为它们提供了更好的代码组织和重用性。
DRF 提供了几种不同层次的基于类的视图:
APIView
: 这是 DRF 最基本的视图类,它是 DjangoView
的子类,但增加了一些 DRF 特有的功能,如请求解析器、认证、权限、限流等。你需要手动处理 HTTP 方法(get
,post
,put
,delete
等)。- Generic API Views: DRF 提供了一系列混合类 (
Mixins
) 和通用类 (Generics
) 来处理常见的 API 操作,如列表获取 (ListModelMixin
), 详情获取 (RetrieveModelMixin
), 创建 (CreateModelMixin
), 更新 (UpdateModelMixin
), 删除 (DestroyModelMixin
)。你可以将这些 Mixins 与GenericAPIView
结合,快速构建实现特定功能的视图。例如,ListAPIView
继承自GenericAPIView
和ListModelMixin
,用于获取资源列表。 - ViewSets: 视图集 (
ViewSet
) 将一组相关的视图逻辑(如列表、详情、创建、更新、删除)集中到一个类中。它们不提供像get()
,post()
这样的方法,而是提供像list()
,retrieve()
,create()
,update()
,destroy()
这样的方法,这些方法对应于常见的 API 操作。ViewSets 通常与 DRF 的路由器 (Routers
) 一起使用,以自动生成 URL 配置。ModelViewSet
是最常见的 ViewSet,它继承自GenericViewSet
和所有主要的 Mixins,为模型提供了完整的 CRUD (Create, Retrieve, Update, Delete) 操作。
对于新手,最快速的方式是直接使用 ModelViewSet
,因为它为模型提供了最全面的 API 功能,并且与路由器配合使用可以大大简化 URL 配置。
编辑 todoapi/views.py
:
“`python
todoapi/views.py
from rest_framework import viewsets
from .models import TodoItem
from .serializers import TodoItemSerializer
class TodoItemViewSet(viewsets.ModelViewSet):
“””
A ViewSet for viewing and editing TodoItem instances.
“””
queryset = TodoItem.objects.all().order_by(‘-created_at’)
serializer_class = TodoItemSerializer
“`
就这样!通过继承 viewsets.ModelViewSet
,我们几乎没有写任何逻辑代码,就创建了一个功能齐全的 API 视图集,可以处理对 TodoItem
资源的列表获取、详情获取、创建、更新和删除请求。
queryset
: 指定了此视图集将操作哪些对象的集合。这里我们获取了所有的TodoItem
对象,并按创建时间倒序排序。serializer_class
: 指定了用于序列化和反序列化数据的序列化器类。
ModelViewSet
内部会自动将接收到的 HTTP 方法(GET, POST, PUT, PATCH, DELETE)映射到其相应的方法上(list
, create
, retrieve
, update
, partial_update
, destroy
)。
第五步:配置 URL (URLs)
传统上,你需要在 urls.py
文件中手动为每个视图方法配置 URL 模式。但当你使用 ViewSets 时,DRF 的路由器可以自动为你完成这项工作。这使得 URL 配置变得异常简单和直观。
-
在应用中创建
urls.py
文件在
todoapi
目录下创建一个新的文件urls.py
:“`python
todoapi/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import TodoItemViewSet创建一个路由器实例
router = DefaultRouter()
注册 ViewSet
参数1: URL 前缀,例如 ‘todos’
参数2: 关联的 ViewSet
参数3: 可选,用于名称空间的 basename
router.register(r’todos’, TodoItemViewSet, basename=’todoitem’)
ViewSets 将自动生成以下 URL 模式:
/todos/ (GET: list, POST: create)
/todos/{id}/ (GET: retrieve, PUT: update, PATCH: partial_update, DELETE: destroy)
urlpatterns = [
# 将路由器生成的 URL 包含到 urlpatterns 中
path(”, include(router.urls)),
]
“`DefaultRouter
: 这是 DRF 提供的一个简单的路由器,可以为注册的 ViewSets 自动生成标准的 URL 配置。router.register(r'todos', TodoItemViewSet, basename='todoitem')
: 这一行告诉路由器为TodoItemViewSet
生成 URL。r'todos'
是这个资源的基本 URL 前缀。basename='todoitem'
是用来生成 URL 名称的基名,即使不指定,DRF 也会尝试从 QuerySet 推断,但显式指定是一个好习惯。
-
在项目主
urls.py
中包含应用的 URL编辑项目根目录下的
myapiproject/urls.py
文件,将todoapi
应用的 URL 配置包含进来:“`python
myapiproject/urls.py
from django.contrib import admin
from django.urls import path, includeurlpatterns = [
path(‘admin/’, admin.site.urls),
# 将 todoapi 应用的 URL 包含在 ‘/api/’ 路径下
path(‘api/’, include(‘todoapi.urls’)),
]
“`我们将 API 的入口点设置在
/api/
路径下。这意味着我们的 ToDo API 资源的完整 URL 将以/api/todos/
开头。
第六步:测试 API (可浏览 API)
DRF 最棒的特性之一就是其内置的“可浏览 API”(Browsable API)。当你通过浏览器访问 DRF 视图的 URL 时,如果请求的是 HTML 格式(浏览器默认行为),DRF 会返回一个漂亮的、交互式的 HTML 页面,而不是原始的 JSON 或 XML 数据。这个页面不仅展示了 API 的输出,还提供了表单界面,方便你测试各种 HTTP 方法(GET, POST, PUT, DELETE)。
-
启动开发服务器
确保你在虚拟环境中,并位于项目根目录下,然后启动 Django 开发服务器:
bash
python manage.py runserver -
访问可浏览 API
打开你的 Web 浏览器,访问
http://127.0.0.1:8000/api/todos/
。你应该会看到一个类似下图的页面(具体样式可能因 DRF 版本略有不同):
- 页面顶部显示了当前的 URL 和允许的 HTTP 方法 (GET, POST)。
- 下方显示了资源的列表(目前应该是空的,因为我们还没创建任何事项)。
- 底部会有一个用于创建新资源的表单 (如果允许 POST 方法)。
测试 GET 请求:
直接访问http://127.0.0.1:8000/api/todos/
就是在执行 GET 请求以获取列表。
尝试访问http://127.0.0.1:8000/api/todos/{id}/
(其中{id}
是一个待办事项的 ID) 来获取单个事项的详情(执行 GET 请求)。目前还没有数据,访问详情页会返回 404。测试 POST 请求 (创建资源):
在http://127.0.0.1:8000/api/todos/
页面的底部,你会看到一个表单。填写title
和可选的description
(completed 字段通常有默认值或不在创建时设置),然后点击 “POST” 按钮。
如果成功,页面会刷新,显示你刚刚创建的待办事项的详情页面(这实际上是一个 POST 请求成功后,DRF 重定向或返回了新创建资源的详情),同时顶部允许的方法会变为 GET, PUT, PATCH, DELETE。列表页 (/api/todos/
) 也会显示新的事项。测试 PUT 请求 (完全更新资源):
访问某个事项的详情页,例如http://127.0.0.1:8000/api/todos/1/
(假设 ID 为 1)。页面底部会出现一个表单,预填充了当前事项的数据。修改所有字段的值,然后点击 “PUT” 按钮。
注意: PUT 请求要求你提交所有字段的数据,即使有些字段你没有修改。如果某个必填字段在 PUT 请求中没有提交,会报错或清空该字段。测试 PATCH 请求 (部分更新资源):
访问某个事项的详情页,例如http://127.0.0.1:8000/api/todos/1/
。页面底部会出现一个表单。这次,你只需要修改你想更新的字段的值 (例如只修改completed
字段为true
),然后点击 “PATCH” 按钮。
PATCH 请求只更新提交的字段,不会影响未提交的字段。这通常比 PUT 请求更灵活。测试 DELETE 请求 (删除资源):
访问某个事项的详情页,例如http://127.0.0.1:8000/api/todos/1/
。页面底部会有一个 “DELETE” 按钮。点击它,然后确认删除。事项将被删除,页面会显示一个空的响应或重定向。使用其他工具测试:
除了可浏览 API,你也可以使用curl
命令行工具或 Postman/Insomnia 等 API 测试工具来测试你的 API。例如,使用curl
发送一个 GET 请求:bash
curl http://127.0.0.1:8000/api/todos/使用
curl
发送一个 POST 请求创建事项:bash
curl -X POST \
http://127.0.0.1:8000/api/todos/ \
-H 'Content-Type: application/json' \
-d '{
"title": "学习 DRF",
"description": "完成 DRF 快速入门教程"
}'这些工具对于模拟客户端请求和自动化测试非常有用。
通过以上步骤,你就成功构建了一个基本的、功能完整的 ToDo 列表 RESTful API,并学会了如何使用可浏览 API 进行交互和测试。
核心概念回顾与进阶提示
到现在为止,我们已经快速地使用了 DRF 的几个核心组件:
- Models: Django 模型定义了数据的结构。
- Serializers: 负责数据的序列化和反序列化,以及验证。
ModelSerializer
是快速创建基于模型序列化器的利器。 - Views: 处理请求和业务逻辑。
ModelViewSet
提供了一套标准的 CRUD 操作实现,极大地减少了代码量。 - Routers: 为 ViewSets 自动生成 URL 配置,简化了 URL 管理。
- Browsable API: 方便开发者和使用者进行API的交互和测试。
这是一个典型的使用 DRF 快速构建 API 的流程。对于大多数基于模型的简单 CRUD API,ModelSerializer
, ModelViewSet
, 和 DefaultRouter
的组合是最高效的方式。
当然,DRF 的功能远不止这些。完成快速入门后,你可以进一步探索以下进阶主题:
- 认证 (Authentication): 如何识别谁在发送请求(例如 Token 认证、Session 认证)。
- 权限 (Permissions): 如何控制用户是否可以执行某个操作(例如只有登录用户才能创建事项,只有事项创建者才能修改或删除)。DRF 提供了
IsAuthenticated
,IsAdminUser
,IsOwner
等内置权限类,也支持自定义权限。 - 过滤 (Filtering): 如何根据查询参数过滤资源列表(例如只获取已完成的事项)。通常结合
django-filter
库使用。 - 分页 (Pagination): 如何将大量结果集分成小块返回,提高效率。DRF 提供了多种分页器。
- 限流 (Throttling): 如何限制用户或 IP 在一定时间内的请求频率,防止滥用。
- 版本控制 (Versioning): 如何管理 API 的不同版本,以便在不破坏现有客户端的情况下进行修改。
- 自定义字段和序列化器方法: 在序列化器中添加不是模型字段的计算字段,或自定义字段的序列化/反序列化逻辑。
- 嵌套序列化器: 处理模型之间的关联关系,例如在获取用户详情时包含该用户创建的所有待办事项。
- API 文档: 使用
drf-yasg
或coreapi
/openapi
等工具自动生成 API 文档。 - 测试: 编写单元测试和集成测试来验证 API 的功能和健壮性。
这些进阶功能使得 DRF 能够应对各种复杂场景的需求。学习这些内容将帮助你构建更安全、高效和易于维护的 API。
总结
恭喜你!通过本文的学习,你已经成功搭建了 DRF 环境,理解了序列化器、视图和路由器的基本作用,并通过一个实际的 ToDo 列表例子,亲手构建并测试了一个完整的 RESTful API。
DRF 凭借其丰富的功能和对 Django 生态的良好集成,成为了 Python 世界中最受欢迎的 API 构建框架之一。它通过提供诸如序列化器、通用视图、视图集、路由器以及可浏览 API 等强大工具,极大地提高了 API 开发的效率。
记住,快速入门只是第一步。要真正掌握 DRF,还需要不断地实践和深入学习其文档。尝试在你的 Django 项目中构建更多不同类型的 API,探索 DRF 提供的各种进阶功能。
希望这篇详细的入门指南能帮助你顺利迈出使用 DRF 构建 API 的第一步。祝你在 DRF 的学习旅程中一切顺利!