DRF 教程:从零开始搭建 RESTful API
欢迎来到 Django REST Framework (DRF) 的世界!在本教程中,我们将一步步地学习如何使用 DRF 从零开始搭建一个功能完善的 RESTful API。无论您是 Django 的初学者还是希望将其与 API 开发结合的资深开发者,本文都将为您提供清晰的指导。
什么是 RESTful API?为什么选择 DRF?
在深入代码之前,让我们快速了解一下基本概念:
- REST (Representational State Transfer): 是一种软件架构风格,用于设计网络应用程序。它定义了一组约束,当一个系统遵循这些约束时,它就被认为是 RESTful 的。RESTful API 的核心思想是使用标准的 HTTP 方法(GET, POST, PUT, DELETE 等)对资源进行操作。
- API (Application Programming Interface): 是一种允许不同软件系统之间进行通信的接口。
- RESTful API: 就是遵循 REST 架构风格的 API,它通常通过 HTTP 协议进行通信,并以 JSON 或 XML 等格式交换数据。
为什么选择 Django REST Framework (DRF)?
Django 本身是一个功能强大的 Web 框架,但它主要面向构建传统的 Web 应用程序,提供 HTML 页面。当我们需要构建现代的、前后端分离的应用程序,或者为移动应用提供数据接口时,就需要一个专门的工具来创建 API。DRF 正是为此而生:
- Django 的扩展: 它建立在 Django 之上,充分利用了 Django 的 ORM、认证系统和各种插件。如果您熟悉 Django,那么学习 DRF 将会非常顺利。
- 易于使用: 提供了强大的工具集,使得构建 API 变得非常简单快捷。
- 功能丰富: 包括序列化器、认证、权限、限流、视图集、路由器等开箱即用的功能。
- 强大的社区和文档: 拥有活跃的社区和详尽的官方文档,遇到问题很容易找到解决方案。
- 可浏览的 API: 自动生成美观且易于调试的 Web 可浏览 API,方便开发和测试。
现在,让我们开始动手搭建第一个 API 吧!
1. 环境准备与项目初始化
在开始之前,请确保您的系统已安装 Python 和 pip。
1.1 创建并激活虚拟环境 (推荐)
良好的开发实践是从虚拟环境开始。
“`bash
创建虚拟环境
python -m venv venv
激活虚拟环境 (Windows)
.\venv\Scripts\activate
激活虚拟环境 (macOS/Linux)
source venv/bin/activate
“`
1.2 安装 Django 和 Django REST Framework
激活虚拟环境后,安装必要的库。
bash
pip install Django djangorestframework
1.3 创建 Django 项目和应用
我们将创建一个名为 myapi_project 的项目和 todos 应用,用于管理待办事项。
“`bash
创建 Django 项目
django-admin startproject myapi_project .
创建 Django 应用
python manage.py startapp todos
“`
现在您的项目结构应该类似这样:
myapi_project/
├── manage.py
├── myapi_project/
│ ├── __init__.py
│ ├── asgi.py
│ ├── settings.py
│ ├── urls.py
│ └── wsgi.py
└── todos/
├── migrations/
├── __init__.py
├── admin.py
├── apps.py
├── models.py
├── tests.py
└── views.py
1.4 注册应用和 DRF
打开 myapi_project/settings.py,在 INSTALLED_APPS 列表中添加 rest_framework 和您的应用 todos。
“`python
myapi_project/settings.py
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
# 第三方应用
‘rest_framework’,
# 自己的应用
‘todos’,
]
… 其他设置 …
“`
2. 定义数据模型 (Models)
我们将创建一个简单的 Todo 模型,包含 title(标题)、description(描述)和 completed(是否完成)字段。
打开 todos/models.py 并添加以下代码:
“`python
todos/models.py
from django.db import models
class Todo(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
“`
2.1 数据库迁移
定义模型后,需要进行数据库迁移。
bash
python manage.py makemigrations todos
python manage.py migrate
3. 创建序列化器 (Serializers)
序列化器是 DRF 的核心组件之一。它们负责将 Django 模型实例(复杂数据类型)转换为 JSON/XML 等可传输的数据格式,以及反之(从传入的 JSON/XML 数据验证并转换回 Django 模型实例)。
在 todos 应用目录下创建一个新文件 todos/serializers.py:
“`python
todos/serializers.py
from rest_framework import serializers
from .models import Todo
class TodoSerializer(serializers.ModelSerializer):
class Meta:
model = Todo
fields = (‘id’, ‘title’, ‘description’, ‘completed’, ‘created_at’)
read_only_fields = (‘created_at’,) # created_at 字段只读
“`
这里我们使用了 ModelSerializer,它是一个非常方便的快捷方式,可以自动为模型生成一系列字段。fields 元组指定了我们希望在 API 中公开的模型字段。read_only_fields 用于指定那些只在读取时显示,创建/更新时无需提供的字段。
4. 创建视图 (Views)
视图负责处理传入的 HTTP 请求,与模型交互,并使用序列化器准备响应数据。DRF 提供了多种视图类型,从低级的 APIView 到高级的 ModelViewSet,让您可以根据需求选择合适的抽象级别。
我们将从 APIView 开始,逐步过渡到更简洁的 GenericAPIView 和 ModelViewSet。
打开 todos/views.py。
4.1 使用 APIView (基础但灵活)
APIView 提供了与 Django View 类似的灵活性,但增加了 DRF 的请求和响应对象、认证、权限和限流等功能。
“`python
todos/views.py (APIView 示例)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from django.http import Http404
from .models import Todo
from .serializers import TodoSerializer
class TodoListCreateAPIView(APIView):
“””
列出所有 Todo 或创建一个新的 Todo。
“””
def get(self, request, format=None):
todos = Todo.objects.all()
serializer = TodoSerializer(todos, many=True) # many=True 表示序列化一个查询集
return Response(serializer.data)
def post(self, request, format=None):
serializer = TodoSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
class TodoDetailAPIView(APIView):
“””
检索、更新或删除一个 Todo 实例。
“””
def get_object(self, pk):
try:
return Todo.objects.get(pk=pk)
except Todo.DoesNotExist:
raise Http404
def get(self, request, pk, format=None):
todo = self.get_object(pk)
serializer = TodoSerializer(todo)
return Response(serializer.data)
def put(self, request, pk, format=None):
todo = self.get_object(pk)
serializer = TodoSerializer(todo, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, pk, format=None):
todo = self.get_object(pk)
todo.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
“`
这种方法虽然清晰,但对于简单的 CRUD 操作来说代码量较大,且重复性高。
4.2 使用 GenericAPIView 和 Mixins (更简洁)
DRF 提供了 GenericAPIView,它继承自 APIView,并预设了一些常用的属性和方法,如 queryset 和 serializer_class。结合 mixins(混合类),我们可以更优雅地实现 CRUD 操作。
“`python
todos/views.py (GenericAPIView 和 Mixins 示例)
请注释掉或删除前面的 APIView 示例代码,以免冲突
from rest_framework import generics, mixins
… (models 和 serializers 导入保持不变)
class TodoListCreateGenericView(generics.GenericAPIView,
mixins.ListModelMixin,
mixins.CreateModelMixin):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
class TodoRetrieveUpdateDestroyGenericView(generics.GenericAPIView,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
def get(self, request, *args, **kwargs):
return self.retrieve(request, *args, **kwargs)
def put(self, request, *args, **kwargs):
return self.update(request, *args, **kwargs)
def patch(self, request, *args, **kwargs): # PATCH 用于部分更新
return self.partial_update(request, *args, **kwargs)
def delete(self, request, *args, **kwargs):
return self.destroy(request, *args, **kwargs)
“`
这里我们使用了 ListModelMixin、CreateModelMixin、RetrieveModelMixin、UpdateModelMixin 和 DestroyModelMixin,它们提供了实现相应操作的逻辑。
4.3 使用 generics.*APIView (最常用快捷方式)
DRF 进一步封装了 GenericAPIView 和 mixins 的组合,提供了 generics 模块中的具体视图类。这是最常见且推荐的方式,因为它代码量最少。
“`python
todos/views.py (generics.*APIView 示例)
请注释掉或删除前面的所有视图示例代码,只保留此部分
from rest_framework import generics
from .models import Todo
from .serializers import TodoSerializer
class TodoListCreateAPIView(generics.ListCreateAPIView):
“””
列出所有 Todo 或创建一个新的 Todo。
“””
queryset = Todo.objects.all()
serializer_class = TodoSerializer
class TodoRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
“””
检索、更新或删除一个 Todo 实例。
“””
queryset = Todo.objects.all()
serializer_class = TodoSerializer
“`
这段代码实现了与 APIView 示例完全相同的功能,但代码量大大减少。这就是 generics 视图的强大之处。
4.4 使用 ViewSet 和 Router (处理一组相关操作)
ViewSet 是一种更高级的抽象,它将一组相关的视图逻辑(如列表、创建、详情、更新、删除)打包到一个类中。结合 Router 可以自动生成 URL 模式,进一步简化 URL 配置。
“`python
todos/views.py (ViewSet 示例)
请注释掉或删除前面的所有视图示例代码,只保留此部分
from rest_framework import viewsets
from .models import Todo
from .serializers import TodoSerializer
class TodoViewSet(viewsets.ModelViewSet):
“””
允许用户查看、编辑和删除 Todo 实例的 API 视图集。
“””
queryset = Todo.objects.all()
serializer_class = TodoSerializer
“`
ModelViewSet 提供了完整的 create, retrieve, update, partial_update, destroy 和 list 操作。
5. 配置 URL 路由
为了让您的 API 能够访问,我们需要将视图映射到 URL。
5.1 为 generics.*APIView 配置 URL
首先,在 todos 应用目录下创建 todos/urls.py 文件:
“`python
todos/urls.py
from django.urls import path
from .views import TodoListCreateAPIView, TodoRetrieveUpdateDestroyAPIView
urlpatterns = [
path(‘todos/’, TodoListCreateAPIView.as_view(), name=’todo-list-create’),
path(‘todos/
]
“`
然后,将 todos 应用的 URL 包含到项目的根 URL 配置中。打开 myapi_project/urls.py:
“`python
myapi_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘todos.urls’)), # 将 todos 应用的 URL 包含进来
]
“`
5.2 为 ViewSet 和 Router 配置 URL (如果选择 ViewSet)
如果您选择使用 ViewSet,URL 配置会更加简单。
首先,删除 todos/urls.py 中为 generics.*APIView 配置的代码。
然后,修改 todos/urls.py 如下:
“`python
todos/urls.py (ViewSet 示例)
from rest_framework.routers import DefaultRouter
from .views import TodoViewSet
router = DefaultRouter()
router.register(r’todos’, TodoViewSet, basename=’todo’) # r’todos’ 是 URL 前缀
urlpatterns = router.urls
“`
DefaultRouter 会自动为 TodoViewSet 生成列表、详情等 URL 模式。basename 参数用于在 URL 名称中生成前缀,例如 todo-list, todo-detail。
myapi_project/urls.py 的配置保持不变:
“`python
myapi_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘todos.urls’)), # 包含 todos 应用的 URL
]
“`
在本教程中,为了简洁和DRF的典型用法,我们推荐使用 generics.*APIView 或 ViewSet。后续测试将基于 ViewSet 进行演示,因为其更为通用和强大。
6. 运行服务器并测试 API
现在,我们已经完成了 API 的基本搭建。运行 Django 开发服务器:
bash
python manage.py runserver
打开浏览器,访问 http://127.0.0.1:8000/api/todos/。
您应该会看到 DRF 提供的可浏览 API 界面!这是一个非常方便的功能,允许您通过浏览器直接与 API 交互,进行 GET、POST、PUT、DELETE 等操作。
测试操作 (假设您使用了 TodoViewSet):
- GET (获取所有 Todo):
访问http://127.0.0.1:8000/api/todos/。您应该会看到一个空的列表(因为还没有数据)。 - POST (创建一个 Todo):
在浏览器界面的底部,您会看到一个表单。填写title和description,completed可以选择或留空(默认为 False)。点击POST。如果成功,您将看到新创建的 Todo 对象。 - GET (获取单个 Todo):
创建一些 Todo 后,访问http://127.0.0.1:8000/api/todos/1/(假设 id 为 1)。 - PUT/PATCH (更新 Todo):
访问http://127.0.0.1:8000/api/todos/1/。在底部表单中修改数据,点击PUT(完全替换) 或PATCH(部分更新)。 - DELETE (删除 Todo):
访问http://127.0.0.1:8000/api/todos/1/。点击DELETE按钮。
您也可以使用 curl 或 Postman/Insomnia 等工具进行测试。
使用 curl 示例:
“`bash
创建一个 Todo
curl -X POST -H “Content-Type: application/json” -d ‘{“title”: “学习 DRF”, “description”: “完成 DRF 教程的学习”, “completed”: false}’ http://127.0.0.1:8000/api/todos/
获取所有 Todo
curl http://127.0.0.1:8000/api/todos/
获取 ID 为 1 的 Todo
curl http://127.0.0.1:8000/api/todos/1/
更新 ID 为 1 的 Todo
curl -X PUT -H “Content-Type: application/json” -d ‘{“title”: “DRF 教程完成”, “description”: “已经完成了 DRF 教程的学习”, “completed”: true}’ http://127.0.0.1:8000/api/todos/1/
删除 ID 为 1 的 Todo
curl -X DELETE http://127.0.0.1:8000/api/todos/1/
“`
7. 认证与权限 (Authentication & Permissions)
目前我们的 API 是完全公开的,任何人都可以访问和修改数据。在实际项目中,这通常是不可接受的。DRF 提供了灵活的认证和权限系统来保护您的 API。
7.1 认证 (Authentication)
认证用于验证用户的身份。DRF 支持多种认证方案,如 SessionAuthentication (用于 Django 管理后台和可浏览 API)、TokenAuthentication、BasicAuthentication、OAuth2Authentication 等。
全局配置认证类:
在 myapi_project/settings.py 中添加或修改 REST_FRAMEWORK 配置:
“`python
myapi_project/settings.py
REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.SessionAuthentication’,
‘rest_framework.authentication.TokenAuthentication’, # 如果您想使用基于 Token 的认证
],
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticated’, # 默认只允许认证用户访问
],
}
“`
为了使用 TokenAuthentication,您需要安装 rest_framework.authtoken 应用:
“`python
myapi_project/settings.py
INSTALLED_APPS = [
# …
‘rest_framework’,
‘rest_framework.authtoken’, # 添加此行
‘todos’,
]
“`
并进行迁移:
bash
python manage.py makemigrations
python manage.py migrate
现在,如果您尝试访问 API,会发现需要登录。在可浏览 API 中,您可以登录 Django 管理员账户(如果您创建过)来继续操作。
7.2 权限 (Permissions)
权限用于确定经过认证的用户是否有权执行特定的操作。DRF 提供了 AllowAny、IsAuthenticated、IsAdminUser、IsAuthenticatedOrReadOnly 等权限类。
视图级别配置权限:
您也可以在特定的视图上覆盖全局权限:
“`python
todos/views.py
from rest_framework.permissions import IsAdminUser, IsAuthenticatedOrReadOnly
… 其他导入 …
class TodoViewSet(viewsets.ModelViewSet):
queryset = Todo.objects.all()
serializer_class = TodoSerializer
# permission_classes = [IsAdminUser] # 只有管理员用户可以完全操作
permission_classes = [IsAuthenticatedOrReadOnly] # 认证用户可读写,未认证用户只读
“`
8. 总结与展望
恭喜您!您已经成功地从零开始搭建了一个功能完善的 RESTful API,并了解了 DRF 的核心组件。
在本教程中,我们学习了:
- DRF 的基本概念和优势。
- 如何设置 Django 项目并集成 DRF。
- 如何定义 Django 模型。
- 如何使用序列化器将模型数据转换为 API 友好的格式。
- 如何使用
APIView、GenericAPIView和ViewSet构建 API 视图。 - 如何配置 URL 路由。
- 如何通过可浏览 API 和
curl测试 API。 - 初步了解了 DRF 的认证和权限系统。
下一步您可以探索:
- 过滤、搜索和排序: DRF 提供了强大的工具来处理这些常见的 API 需求。
- 分页: 处理大量数据时必不可少。
- 自定义字段和序列化器: 创建更复杂的序列化逻辑。
- 限流 (Throttling): 控制客户端的请求频率。
- 测试: 编写单元测试和集成测试来确保 API 的健壮性。
- 部署: 将您的 API 部署到生产环境。
- 更复杂的认证方案: 如 OAuth2。
Django REST Framework 是一个非常强大且灵活的工具,可以帮助您快速高效地构建高质量的 API。继续实践和探索,您将能够利用它来构建各种复杂的应用程序后端。
祝您编程愉快!
好的,我已经为您撰写了一篇详细描述“DRF 教程:从零开始搭建 RESTful API”的文章。请查阅。