拥抱 API 开发:Django REST Framework (DRF) 入门宝典
在现代 Web 开发中,应用程序之间的数据交互变得越来越重要。无论是为移动应用提供后端服务,还是为前端单页面应用 (SPA) 提供数据接口,构建一个高效、稳定且易于维护的 API (Application Programming Interface) 都是核心需求。RESTful API 作为一种常见且强大的设计风格,已经被广泛采纳。
对于 Python 和 Django 开发者而言,构建 RESTful API 的首选框架莫过于 Django REST Framework (DRF)。DRF 是 Django 官方推荐的 RESTful API 开发框架,它强大而灵活,提供了丰富的功能来简化序列化、视图处理、认证、权限、限流等 API 开发中的常见任务。
本篇文章将带你从零开始,一步步深入了解 DRF 的核心概念和使用方法,构建一个简单的 RESTful API 示例。我们将详细讲解 DRF 的主要组件,并通过实际代码演示如何构建一个用于管理书籍信息的 API。
预计阅读时间较长,内容深入,请准备好你的开发环境,跟随本文一起开启 DRF 的学习之旅吧!
第一章:API 和 RESTful 概念速览
在正式接触 DRF 之前,我们先简要回顾一下 API 和 RESTful 的基本概念。
什么是 API?
API,全称 Application Programming Interface (应用程序接口),本质上是不同软件系统之间相互通信的桥梁。它定义了一系列规则、协议和工具,允许不同的应用程序相互交互,共享数据和功能。
想象一下餐厅里的服务员。你(一个应用程序)不需要知道厨房(另一个应用程序)是如何准备食物的细节,你只需要通过菜单(API 定义的接口)告诉服务员(API 调用)你想要什么,服务员会将你的点餐传递给厨房,并将准备好的食物(数据)送给你。
什么是 RESTful API?
REST,全称 Representational State Transfer (表述性状态转移),是一种软件架构风格,由 Roy Fielding 在其博士论文中提出。RESTful API 是遵循 REST 架构原则设计的 API。虽然 REST 本身不是一个严格的标准,但它提供了一套设计原则,使得 API 更易于理解、扩展和维护。
REST 的核心原则包括:
- 客户端-服务器 (Client-Server):客户端和服务器职责分离,提高了独立性和可移植性。
- 无状态 (Stateless):服务器不存储客户端的会话状态。每个请求都包含处理该请求所需的所有信息。
- 统一接口 (Uniform Interface):通过一致的方式与资源进行交互,主要体现在:
- 资源 (Resources):API 中的所有信息都被建模为资源,具有唯一的标识符(URI)。
- 通过表述操作资源 (Manipulation of Resources Through Representations):客户端通过资源的某种表述(如 JSON、XML)来改变资源的状态。
- 自描述消息 (Self-descriptive Messages):消息本身包含足够的信息来描述如何处理它。
- 超媒体即应用状态的引擎 (Hypermedia as the Engine of Application State, HATEOAS):通过在响应中包含超链接,客户端可以通过链接发现并执行下一步操作(这是 RESTful 更高级的原则,初学者可以先了解概念)。
- 可缓存 (Cacheable):客户端或中介可以缓存响应,提高性能。
- 分层系统 (Layered System):服务器和客户端之间的中间层(如代理、网关)对客户端是透明的,有助于提高可伸缩性和灵活性。
在实践中,设计 RESTful API 通常意味着:
- 使用 URI 来标识资源(例如:
/books
,/books/1
)。 - 使用 HTTP 方法来操作资源(GET 获取,POST 创建,PUT 更新,PATCH 部分更新,DELETE 删除)。
- 使用 HTTP 状态码表示操作结果(例如:200 OK, 201 Created, 400 Bad Request, 404 Not Found, 500 Internal Server Error)。
- 通常使用 JSON 或 XML 作为数据交换格式(JSON 更为流行)。
第二章:DRF 简介与环境准备
为什么选择 DRF?
DRF 是构建 Django API 的事实标准,拥有众多优势:
- 强大且灵活:提供了丰富的功能,可以处理各种复杂的 API 需求。
- 集成 Django:与 Django 的 ORM、URL 路由、认证系统等无缝集成。
- 序列化器 (Serializers):简化了 Django 模型对象或其他数据结构的序列化和反序列化过程,同时提供了强大的数据验证功能。
- 视图类 (View Classes):提供了多种视图类,从简单的 APIView 到功能强大的 ModelViewSet,极大地减少了 boilerplate 代码。
- 认证与权限 (Authentication & Permissions):内置了多种认证和权限机制,易于控制 API 的访问。
- 可浏览 API (Browsable API):提供了一个用户友好的 Web 界面,方便开发者测试和查看 API。
- 文档生成:支持自动生成 API 文档。
- 活跃的社区:庞大的用户群体和活跃的社区支持。
环境准备
在开始之前,请确保你已经安装了 Python 和 Django。如果还没有,请先安装。
-
创建并激活虚拟环境 (推荐):
“`bash
python -m venv myapi-venvWindows
myapi-venv\Scripts\activate
macOS/Linux
source myapi-venv/bin/activate
“` -
安装 Django 和 DRF:
bash
pip install Django djangorestframework -
创建 Django 项目:
bash
django-admin startproject myapi .
(注意最后的.
表示在当前目录下创建项目,如果你想在子目录下创建,可以去掉.
并进入该子目录) -
创建 Django 应用:
bash
python manage.py startapp booksapi
我们将使用booksapi
这个应用来构建书籍 API。 -
注册应用和 DRF:
打开myapi/settings.py
文件,在INSTALLED_APPS
列表中添加'booksapi'
和'rest_framework'
。“`python
myapi/settings.py
INSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘rest_framework’, # 添加这一行
‘booksapi’, # 添加这一行
]… 其他设置
“`
至此,你的 Django 项目已经配置好 DRF 了。
第三章:构建第一个 DRF API – 书籍管理
我们将构建一个简单的 API,用于管理书籍信息,包括书名 (title) 和作者 (author)。
步骤 1:定义模型 (Model)
在 booksapi/models.py
文件中定义 Book
模型:
“`python
booksapi/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(null=True, blank=True) # 添加发布日期字段
def __str__(self):
return f"{self.title} by {self.author}"
“`
运行数据库迁移:
bash
python manage.py makemigrations
python manage.py migrate
步骤 2:创建序列化器 (Serializer)
序列化器是 DRF 中最核心的概念之一。它的主要作用是:
- 序列化 (Serialization):将复杂的 Python 数据类型(如 Django 模型实例、查询集)转换成易于传输的格式,如 JSON、XML。
- 反序列化 (Deserialization):将接收到的数据(如 JSON 请求体)转换回 Python 数据类型,同时进行数据验证。
在 booksapi
应用目录下创建一个新的文件 serializers.py
:
“`python
booksapi/serializers.py
from rest_framework import serializers
from .models import Book
方法一:使用 Serializer 手动定义字段
class BookSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True) # read_only=True 表示该字段只用于序列化输出,不用于反序列化输入
title = serializers.CharField(max_length=200)
author = serializers.CharField(max_length=100)
published_date = serializers.DateField(required=False, allow_null=True) # required=False 表示该字段非必填
def create(self, validated_data):
“””
根据 validated_data 创建并返回一个新的 Book 实例。
“””
return Book.objects.create(**validated_data)
def update(self, instance, validated_data):
“””
根据 validated_data 更新并返回现有的 Book 实例。
“””
instance.title = validated_data.get(‘title’, instance.title)
instance.author = validated_data.get(‘author’, instance.author)
instance.published_date = validated_data.get(‘published_date’, instance.published_date)
instance.save()
return instance
方法二(更常用):使用 ModelSerializer
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
# fields = ‘all‘ # 包含模型中的所有字段
fields = [‘id’, ‘title’, ‘author’, ‘published_date’] # 或者明确指定需要包含的字段
# exclude = [‘some_field_to_exclude’] # 或者明确指定需要排除的字段
“`
ModelSerializer
是 DRF 提供的一个强大工具,它可以自动推断模型字段,并为创建和更新操作提供默认的实现(即上面的 create
和 update
方法)。这大大简化了序列化器的编写,特别是在处理与模型直接对应的 API 时。我们通常推荐使用 ModelSerializer
。
在 Meta
类中,我们指定了 model
为 Book
,并使用 fields = '__all__'
或一个字段列表来指定应该包含哪些模型字段在序列化器中。id
字段通常是自动包含的,但显式列出可以更清晰。read_only=True
对于 id
字段是必要的,因为它是在数据库中生成的,不应该由客户端提供。ModelSerializer
会自动处理这些细节。
步骤 3:创建视图 (View)
视图负责处理 API 请求,包括接收请求数据、调用序列化器进行验证和转换、与模型交互(查询、创建、更新、删除)以及生成响应。
DRF 提供了多种视图类型,从简单的函数式视图到功能丰富的类式视图。我们将从最基础的开始,逐步介绍到最常用的类型。
3.1 函数式视图 (@api_view)
可以使用 @api_view
装饰器将标准的 Django 函数式视图转换为 DRF 视图。
“`python
booksapi/views.py (示例 – 函数式视图,暂时不使用在最终项目中)
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer
@api_view([‘GET’, ‘POST’]) # 指定该视图只响应 GET 和 POST 请求
def book_list(request):
“””
列出所有书籍,或创建一个新书籍。
“””
if request.method == ‘GET’:
books = Book.objects.all()
serializer = BookSerializer(books, many=True) # many=True 表示序列化一个查询集(多个对象)
return Response(serializer.data) # serializer.data 包含了序列化后的数据
elif request.method == 'POST':
serializer = BookSerializer(data=request.data) # request.data 是 DRF 处理后的请求体数据
if serializer.is_valid(): # 数据验证
serializer.save() # 保存到数据库(如果使用 ModelSerializer 会自动调用 create 或 update)
return Response(serializer.data, status=status.HTTP_201_CREATED) # 返回创建成功的响应
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) # 返回验证错误
@api_view([‘GET’, ‘PUT’, ‘PATCH’, ‘DELETE’]) # 指定该视图响应特定请求方法
def book_detail(request, pk):
“””
检索、更新或删除一个书籍实例。
“””
try:
book = Book.objects.get(pk=pk) # 根据主键获取书籍
except Book.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND) # 未找到则返回 404
if request.method == 'GET':
serializer = BookSerializer(book) # 序列化单个对象
return Response(serializer.data)
elif request.method == 'PUT' or request.method == 'PATCH':
serializer = BookSerializer(book, data=request.data, partial=(request.method == 'PATCH')) # 更新时传入实例和数据
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
book.delete()
return Response(status=status.HTTP_204_NO_CONTENT) # 删除成功返回 204
“`
函数式视图对于简单的 API 接口非常适用,但随着接口数量和复杂度的增加,会产生大量的重复代码(如获取对象、检查方法、调用序列化器、处理响应)。
3.2 类式视图 (APIView)
DRF 提供了 APIView
类,它是 Django 的 View
类的子类,提供了 DRF 特有的功能(如认证、权限、解析器、渲染器等)。你可以通过定义不同的方法(get()
, post()
, put()
, patch()
, delete()
)来处理不同的 HTTP 请求。
“`python
booksapi/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 # Django 的异常类
from .models import Book
from .serializers import BookSerializer
class BookList(APIView):
“””
列出所有书籍,或创建一个新书籍。
“””
def get(self, request, format=None): # get 方法处理 GET 请求
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
def post(self, request, format=None): # post 方法处理 POST 请求
serializer = BookSerializer(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 BookDetail(APIView):
“””
检索、更新或删除一个书籍实例。
“””
def get_object(self, pk): # 辅助方法,用于获取书籍对象,处理 404 异常
try:
return Book.objects.get(pk=pk)
except Book.DoesNotExist:
raise Http404 # 抛出 Django 的 Http404 异常,DRF 会将其转换为 404 响应
def get(self, request, pk, format=None): # get 方法处理 GET 请求 (带 pk)
book = self.get_object(pk)
serializer = BookSerializer(book)
return Response(serializer.data)
def put(self, request, pk, format=None): # put 方法处理 PUT 请求 (带 pk)
book = self.get_object(pk)
serializer = BookSerializer(book, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def patch(self, request, pk, format=None): # patch 方法处理 PATCH 请求 (带 pk)
book = self.get_object(pk)
serializer = BookSerializer(book, data=request.data, partial=True) # partial=True 启用部分更新
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): # delete 方法处理 DELETE 请求 (带 pk)
book = self.get_object(pk)
book.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
“`
类式视图相比函数式视图结构更清晰,更易于组织代码。但对于标准的 CRUD (创建、读取、更新、删除) 操作,仍然有许多重复的逻辑。
3.3 通用视图 (Generic Views)
DRF 提供了一系列通用视图类,它们建立在 APIView
之上,提供了针对常见任务的默认实现,如列表显示、详情显示、创建、更新、删除等。通过简单地设置 queryset
和 serializer_class
属性,你就可以实现完整的 CRUD 视图。
常用的通用视图包括:
CreateAPIView
: 只处理创建请求。ListAPIView
: 只处理列表显示请求。RetrieveAPIView
: 只处理详情显示请求。UpdateAPIView
: 只处理更新请求。DestroyAPIView
: 只处理删除请求。ListCreateAPIView
: 处理列表显示和创建请求。RetrieveUpdateAPIView
: 处理详情显示和更新请求。RetrieveDestroyAPIView
: 处理详情显示和删除请求。RetrieveUpdateDestroyAPIView
: 处理详情显示、更新和删除请求。
让我们使用通用视图来重写书籍 API:
“`python
booksapi/views.py (示例 – Generic Views,暂时不使用在最终项目中)
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer
class BookListCreate(generics.ListCreateAPIView):
“””
列出所有书籍,或创建一个新书籍。
等价于函数式视图 book_list 或 APIView 的 BookList。
“””
queryset = Book.objects.all() # 指定查询集
serializer_class = BookSerializer # 指定序列化器
class BookRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView):
“””
检索、更新或删除一个书籍实例。
等价于函数式视图 book_detail 或 APIView 的 BookDetail。
“””
queryset = Book.objects.all() # 指定查询集
serializer_class = BookSerializer # 指定序列化器
lookup_field = ‘pk’ # 指定用于查找对象的 URL 参数名,默认为 ‘pk’
“`
通用视图极大地减少了代码量,是我们构建 API 的重要工具。然而,对于需要将多种操作(列表、创建、详情、更新、删除)组合到同一个 URL 路径下的情况(例如 /books/
用于列表和创建,/books/1/
用于详情、更新和删除),我们需要定义两个不同的视图类并配置相应的 URL。这引入了 ViewSet
的概念。
3.4 视图集 (ViewSets)
ViewSet
是 DRF 中一个更高层面的抽象。它不像传统的视图那样处理特定的 HTTP 方法(get
, post
等),而是处理一组相关的 操作 (actions),如 list
, create
, retrieve
, update
, partial_update
, destroy
。
ViewSet
与 URL 的映射通常不是直接在 urls.py
中定义,而是通过 路由器 (Routers) 来完成。路由器可以自动生成 ViewSet 对应操作的 URL 配置,进一步简化 URL 配置。
最常用的视图集是 ModelViewSet
,它直接继承了 GenericViewSet
和多种 Mixins(包含创建、列表、详情、更新、删除操作的实现),非常适合用于与 Django 模型直接对应的 CRUD API。
“`python
booksapi/views.py (最终版本,使用 ModelViewSet)
booksapi/views.py
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework import status
from rest_framework.views import APIView
from django.http import Http404
from rest_framework import generics # 暂时注释掉之前的示例
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
使用 ModelViewSet,它包含了列表、创建、详情、更新、部分更新、删除等所有常用操作的实现
class BookViewSet(viewsets.ModelViewSet):
“””
A ViewSet for viewing and editing Book instances.
提供 ‘list’, ‘create’, ‘retrieve’, ‘update’, ‘partial_update’, ‘destroy’ 等操作。
“””
queryset = Book.objects.all() # 指定查询集
serializer_class = BookSerializer # 指定序列化器
# lookup_field = ‘pk’ # 默认就是 ‘pk’,如果需要使用其他字段作为查找依据,可以修改这里
# filter_backends = [filters.SearchFilter, filters.OrderingFilter] # 示例:添加过滤和排序
# search_fields = [‘title’, ‘author’] # 示例:按书名和作者搜索
# permission_classes = [permissions.IsAuthenticatedOrReadOnly] # 示例:只有认证用户才能修改
“`
ModelViewSet
通过设置 queryset
和 serializer_class
属性,就能自动提供一个完整的 RESTful API 接口集合,包括:
GET /books/
:list
action (获取所有书籍列表)POST /books/
:create
action (创建新书籍)GET /books/{pk}/
:retrieve
action (获取单本书籍详情)PUT /books/{pk}/
:update
action (更新单本书籍,全量更新)PATCH /books/{pk}/
:partial_update
action (部分更新单本书籍)DELETE /books/{pk}/
:destroy
action (删除单本书籍)
这大大简化了视图的编写,尤其是在构建基于模型的 CRUD API 时。
步骤 4:配置 URL
现在我们需要将视图(或视图集)映射到 URL。对于 ViewSets,我们强烈推荐使用 DRF 提供的路由器。
首先,在 booksapi
应用目录下创建一个 urls.py
文件(如果不存在):
“`python
booksapi/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet
创建一个路由器实例
router = DefaultRouter()
注册 ViewSet 到路由器
第一个参数是 URL 前缀
第二个参数是 ViewSet 类
第三个参数是 basename,用于生成 URL 名称,如果 queryset 提供了 .model 属性,可以省略
router.register(r’books’, BookViewSet, basename=’book’)
路由器会为 BookViewSet 生成如下 URL 模式:
/books/ -> list, create
/books/{pk}/ -> retrieve, update, partial_update, destroy
urlpatterns = [
# include(router.urls) 会包含路由器生成的所有 URL
path(”, include(router.urls)),
]
“`
然后,在项目的 urls.py
(myapi/urls.py
) 中包含应用的 URL 配置:
“`python
myapi/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
# 将 booksapi 应用的 URL 配置包含进来,前缀为 ‘api/’
path(‘api/’, include(‘booksapi.urls’)),
# 添加 DRF 的认证登录和退出 URL,方便浏览式 API 使用
path(‘api-auth/’, include(‘rest_framework.urls’, namespace=’rest_framework’)),
]
“`
现在,我们通过简单的配置就完成了 API 的 URL 路由。DefaultRouter
自动处理了 /books/
和 /books/{pk}/
这两种 URL 模式,并将不同的 HTTP 请求方法映射到 BookViewSet
中对应的 action 上。
同时,我们在项目级 urls.py
中添加了 path('api-auth/', include('rest_framework.urls', namespace='rest_framework'))
。这会添加一个登录和退出视图,主要用于 DRF 的 Browsable API,让你可以在浏览器中方便地进行认证。
第四章:测试你的 API – 浏览式 API
DRF 最棒的功能之一就是它的浏览式 API (Browsable API)。当你用浏览器访问一个 DRF 视图的 URL 时,如果你的浏览器接受 text/html
格式的响应(默认情况下浏览器都会接受),DRF 会渲染一个用户友好的 HTML 页面,方便你查看和与 API 交互。
-
运行开发服务器:
bash
python manage.py runserver -
访问 API URL:
打开浏览器,访问http://127.0.0.1:8000/api/books/
你应该能看到一个漂亮的 HTML 页面,显示当前的图书列表(初始是空的)。
- 查看列表 (GET): 页面上方会显示当前 URL (
http://127.0.0.1:8000/api/books/
) 和允许的 HTTP 方法 (GET, POST)。页面中央会显示当前的书籍列表数据(一个空的 JSON 数组[]
)。 - 创建书籍 (POST): 在页面底部的表单区域,你可以看到一个表单,其中包含
title
,author
,published_date
字段。填写信息后,点击 “POST” 按钮,即可向/api/books/
发送一个 POST 请求来创建一本新书。成功后,页面会刷新并显示新创建的书籍数据,状态码通常是 201 Created。 - 查看详情 (GET): 创建几本书后,在列表页面点击任意一本书的 URL (例如
http://127.0.0.1:8000/api/books/1/
),会跳转到该书籍的详情页面。这里你可以看到该书籍的详细信息。 - 更新书籍 (PUT/PATCH): 在详情页面底部,会有一个表单用于更新。
- PUT: 如果你修改表单并点击 PUT,会发送一个 PUT 请求。PUT 通常用于全量更新,即使你只修改一个字段,也需要提供所有字段的值。
- PATCH: 如果你修改表单并点击 PATCH,会发送一个 PATCH 请求。PATCH 用于部分更新,你只需要提供需要修改的字段。DRF 的
ModelSerializer
和ModelViewSet
默认支持 PATCH。
- 删除书籍 (DELETE): 在详情页面,你会看到一个 DELETE 按钮。点击它可以删除当前书籍。成功后通常返回 204 No Content 状态码。
- 查看列表 (GET): 页面上方会显示当前 URL (
这个 Browsable API 是一个非常强大的调试和测试工具,让你在开发过程中无需借助额外的工具(如 Postman 或 curl)就能方便地与你的 API 交互。
第五章:深入理解 DRF 组件
序列化器 (Serializers) 的更多细节
除了基本的序列化和反序列化,序列化器还负责数据验证。当调用 serializer.is_valid()
方法时,它会检查传入的数据是否符合序列化器定义的字段类型、长度、必填性等要求。如果验证失败,serializer.errors
会包含详细的错误信息。
你还可以在序列化器中添加自定义的验证逻辑:
-
字段级验证:定义
validate_<field_name>
方法。“`python
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ‘all‘def validate_title(self, value): """ 验证书名是否已经存在。 """ # self.instance 在更新操作时是当前实例,创建操作时是 None if self.instance is None and Book.objects.filter(title=value).exists(): raise serializers.ValidationError("这本书已经存在了。") # 如果是更新操作,并且书名没有改变,则跳过检查 if self.instance and self.instance.title == value: pass elif Book.objects.filter(title=value).exists(): raise serializers.ValidationError("这本书名已经被使用了。") return value
“`
-
对象级验证:定义
validate
方法。“`python
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = ‘all‘def validate(self, data): """ 检查作者和书名是否相同(一个无意义的示例)。 """ if data.get('title') == data.get('author'): raise serializers.ValidationError("书名和作者不能一样。") return data
“`
序列化器是 DRF 数据处理的核心,理解并能熟练运用它对于构建高质量的 API 至关重要。
视图集 (ViewSets) 和路由器 (Routers) 的工作原理
ModelViewSet
继承自 GenericViewSet
和一些 Mixin 类:
python
class ModelViewSet(mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
mixins.ListModelMixin,
GenericViewSet):
pass
每个 Mixin 都提供了一个或多个 action 的实现:
CreateModelMixin
: 提供create()
action。ListModelMixin
: 提供list()
action。RetrieveModelMixin
: 提供retrieve()
action。UpdateModelMixin
: 提供update()
action。DestroyModelMixin
: 提供destroy()
action。
GenericViewSet
提供了基础的属性(如 queryset
, serializer_class
, lookup_field
)和方法(如 get_object()
, get_queryset()
, get_serializer()
, get_serializer_class()
)。
路由器的工作就是检查 ViewSet 中定义的 action(例如 list
, create
, retrieve
等),并根据这些 action 自动创建 URL 模式,将 HTTP 方法映射到对应的 action 上。
例如,DefaultRouter
对于 BookViewSet
(queryset=Book.objects.all()) 会生成类似如下的 URL 模式:
“`python
伪代码,展示路由器生成的大致映射关系
/books/
url(r’^books/$’, BookViewSet.as_view({‘get’: ‘list’, ‘post’: ‘create’}), name=’book-list’),
/books/{pk}/
url(r’^books/(?P
注意:路由器实际生成的 URL 模式更复杂,这里仅为示意
“`
ViewSet.as_view()
方法是 ViewSet 转换为常规 Django 视图的关键。它接收一个字典,将 HTTP 方法映射到 ViewSet 的 action 名称。路由器就是通过这种方式实现了 ViewSet 和 URL 的自动绑定。
使用 ViewSet 和路由器可以保持视图代码的简洁和一致性,避免手动编写大量重复的 URL 配置。
第六章:超越 CRUD – DRF 的其他功能
本教程专注于入门,但 DRF 的强大远不止于此。了解一些其他重要功能有助于你构建更健壮的 API:
认证 (Authentication)
认证是识别发出请求的客户端身份的过程。DRF 提供了多种认证方式:
SessionAuthentication
: 基于 Django 的 session 和 cookie,适合与 Django 自带的模板或服务器端渲染的应用配合使用,也用于 Browsable API。TokenAuthentication
: 基于 token 的认证,客户端在请求头中发送一个唯一的 token。BasicAuthentication
: 基于 HTTP Basic Auth,客户端在请求头中发送用户名和密码。- OAuth2 (通过第三方包实现)。
你可以在 settings.py
中配置默认的认证类,或者在单个视图类中指定:
“`python
myapi/settings.py
REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.SessionAuthentication’,
‘rest_framework.authentication.TokenAuthentication’,
# … 其他认证类
]
}
booksapi/views.py
from rest_framework.permissions import IsAuthenticated
from rest_framework.authentication import TokenAuthentication # 需要安装 djangorestframework-simplejwt 或类似的 token 包
class BookViewSet(viewsets.ModelViewSet):
# … queryset, serializer_class …
# 只允许认证用户访问
# permission_classes = [IsAuthenticated]
# 同时指定认证类 (会覆盖全局设置)
# authentication_classes = [TokenAuthentication]
“`
权限 (Permissions)
权限是在认证之后进行,用于确定客户端是否有权执行某个操作(例如,是否可以修改某个对象)。DRF 提供了多种权限类:
AllowAny
: 允许任何人访问。IsAuthenticated
: 只允许认证用户访问。IsAdminUser
: 只允许管理员用户访问。IsAuthenticatedOrReadOnly
: 认证用户可以完全访问,未认证用户只能读取。DjangoModelPermissions
: 基于 Django 模型权限。DjangoObjectPermissions
: 基于 Django 对象权限。
你也可以编写自定义的权限类。权限类通常在视图类中通过 permission_classes
属性指定。
分页 (Pagination)
当列表数据量很大时,一次性返回所有数据会导致性能问题。DRF 提供了多种分页器:
PageNumberPagination
: 基于页码的分页,请求中包含?page=N
和?page_size=M
参数。LimitOffsetPagination
: 基于偏移量和限制数量的分页,请求中包含?limit=M&offset=N
参数。CursorPagination
: 基于游标的分页,适用于大型数据集,效率更高,但也更复杂。
可以在 settings.py
中设置全局默认分页器,或者在视图类中指定。
“`python
myapi/settings.py
REST_FRAMEWORK = {
# … authentication, permissions …
‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
‘PAGE_SIZE’: 10 # 默认每页显示 10 条数据
}
booksapi/views.py
from rest_framework.pagination import PageNumberPagination
class LargeResultsSetPagination(PageNumberPagination):
page_size = 100
page_size_query_param = ‘page_size’
max_page_size = 1000
class BookViewSet(viewsets.ModelViewSet):
# … queryset, serializer_class …
# pagination_class = LargeResultsSetPagination # 为这个 ViewSet 指定分页器
“`
过滤和搜索 (Filtering & Searching)
DRF 可以结合 django-filter
或自带的过滤和搜索后端来为 API 添加过滤和搜索功能。
“`python
myapi/settings.py
REST_FRAMEWORK = {
# … other settings …
‘DEFAULT_FILTER_BACKENDS’: [‘rest_framework.filters.SearchFilter’, ‘rest_framework.filters.OrderingFilter’],
}
booksapi/views.py
from rest_framework import filters
class BookViewSet(viewsets.ModelViewSet):
# … queryset, serializer_class …
# 启用搜索和排序 (已在 settings 中全局设置,也可以在这里覆盖)
# filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = [‘title’, ‘author’] # 指定可以搜索的字段
ordering_fields = [‘title’, ‘published_date’] # 指定可以排序的字段
# 例如:访问 /api/books/?search=python&ordering=-published_date
“`
测试
DRF 提供了 APIClient
用于方便地测试 API 视图,类似于 Django 的 Client
,但专为 API 测试设计。
“`python
booksapi/tests.py (示例)
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Book
class BookApiTests(APITestCase):
def setUp(self):
# 创建一些初始数据
Book.objects.create(title=’Book 1′, author=’Author A’)
Book.objects.create(title=’Book 2′, author=’Author B’)
def test_list_books(self):
"""
测试获取书籍列表。
"""
url = reverse('book-list') # 使用 basename 和 action 名称反向解析 URL
response = self.client.get(url, format='json') # 使用 DRF 的 client 发送请求
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 2) # 检查返回的数据数量
self.assertEqual(response.data[0]['title'], 'Book 1')
def test_create_book(self):
"""
测试创建新书籍。
"""
url = reverse('book-list')
data = {'title': 'New Book', 'author': 'New Author'}
response = self.client.post(url, data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Book.objects.count(), 3)
self.assertEqual(Book.objects.get(id=response.data['id']).title, 'New Book')
def test_retrieve_book(self):
"""
测试获取单本书籍详情。
"""
book = Book.objects.get(title='Book 1')
url = reverse('book-detail', args=[book.id])
response = self.client.get(url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(response.data['title'], 'Book 1')
# TODO: 添加 test_update_book, test_partial_update_book, test_delete_book 等测试用例
“`
编写单元测试对于保证 API 的质量和稳定性至关重要。
第七章:总结与展望
恭喜你!通过本文的学习,你已经掌握了 Django REST Framework 的核心概念和基础用法:
- 理解了 API 和 RESTful 的基本原理。
- 学习了如何在 Django 项目中安装和配置 DRF。
- 掌握了 DRF 的主要组件:模型 (Model), 序列化器 (Serializer), 视图 (Views) (特别是 ModelViewSet), 和 路由器 (Router)。
- 构建了一个简单的书籍管理 API 示例。
- 了解并使用了 DRF 强大的浏览式 API 进行测试。
- 初步接触了 DRF 的其他高级功能,如认证、权限、分页和过滤。
这只是 DRF 的冰山一角,但已经足以让你开始构建自己的 RESTful API。下一步,你可以继续深入学习以下主题:
- 更复杂的序列化器应用(嵌套序列化、自定义字段)。
- 自定义 ViewSet 和 Mixins。
- DRF 的各种渲染器 (Renderers) 和解析器 (Parsers)。
- 更详细的认证和权限配置及自定义。
- 限流 (Throttling)。
- API 文档生成 (如使用
drf-yasg
或coreapi
)。 - 更高级的过滤和搜索技术。
- 如何处理文件上传。
- API 版本控制。
DRF 是一个功能丰富且设计精良的框架,它遵循 Django 的“约定优于配置”原则,让你能够快速地构建出符合 RESTful 风格的高质量 API。通过不断实践和深入学习,你将能够利用 DRF 轻松应对各种复杂的 API 开发挑战。
希望这篇详细的教程为你打开了 DRF 的大门。现在,是时候动手实践,开始构建你自己的 API 项目了!