从零开始:掌握 Django REST framework (DRF)
引言:API 时代与 DRF 的崛起
在现代 Web 开发的浪潮中,前后端分离、移动应用、单页应用 (SPA) 已成为主流。这些架构模式的基石,正是强大的 API(应用程序接口)。API 允许不同的软件系统相互通信,交换数据,使得后端可以专注于业务逻辑和数据处理,而前端则负责用户界面的呈现。
对于 Django 开发者而言,构建高质量、可维护且易于使用的 RESTful API 是一个常见的需求。虽然 Django 本身提供了处理 HTTP 请求和返回 JSON/XML 的基础能力,但构建一个完整的 RESTful API 需要处理序列化、反序列化、视图逻辑、认证、权限、分页、过滤、路由等诸多繁琐的任务。如果从头开始手动实现这一切,不仅耗时耗力,而且容易出错。
这时,Django REST framework (DRF) 应运而生。DRF 是一个功能强大且高度灵活的工具包,它建立在 Django 的基础上,极大地简化了构建 Web API 的过程。它提供了一系列开箱即用的组件,如序列化器、通用视图、认证和权限类、分页器、解析器和渲染器,让你能够以前所未有的效率构建功能完备的 API。
掌握 DRF,意味着你能够利用 Django 强大的 ORM 和生态系统,快速地搭建出供前端、移动应用或第三方服务调用的 API。本文将带领你从零开始,一步步深入理解 DRF 的核心概念,并通过一个实际例子,教会你如何用 DRF 构建一个简单的 API。
准备工作:基础与环境搭建
在开始学习 DRF 之前,你需要具备以下基础知识:
- Python 基础: 掌握 Python 的语法、数据结构、函数、类等基本概念。
- Django 基础: 了解 Django 项目结构、MVT(或 MTV)模式、模型 (Models)、ORM (Object-Relational Mapper)、视图 (Views)、URL 路由 (URLs) 等。你需要能够创建一个基本的 Django 项目和应用,并定义模型和执行数据库迁移。
如果你的 Django 基础还不够牢固,建议先花时间回顾一下官方文档或相关的入门教程。
环境搭建:
- 安装 Python: 确保你的系统已经安装了 Python 3.6 或更高版本。
- 创建虚拟环境 (推荐): 使用虚拟环境可以隔离不同项目的依赖,避免冲突。
bash
python -m venv venv - 激活虚拟环境:
- Windows:
venv\Scripts\activate
- macOS/Linux:
source venv/bin/activate
- Windows:
- 安装 Django 和 DRF: 在激活的虚拟环境中安装。
bash
pip install Django djangorestframework
创建 Django 项目与应用
我们将创建一个简单的项目来演示 DRF 的用法。假设我们要创建一个管理产品的 API。
- 创建 Django 项目:
bash
django-admin startproject drf_project .
(注意最后的.
表示在当前目录下创建项目文件) - 创建 Django 应用:
bash
python manage.py startapp products -
注册应用和 DRF: 在
drf_project/settings.py
的INSTALLED_APPS
中添加'products'
和'rest_framework'
。
“`python
# drf_project/settings.pyINSTALLED_APPS = [
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘products’, # 注册你的应用
‘rest_framework’, # 注册 DRF
]… 其他设置
“`
DRF 核心组件:序列化器 (Serializers)
API 的一个主要任务是处理数据的表示和转换。后端通常使用 Python 对象(如 Django 模型实例),而 API 请求和响应通常使用 JSON、XML 等格式。序列化器就是负责在这些格式之间进行转换的组件。
序列化 (Serialization): 将复杂的 Python 数据类型(如 Django 模型实例、QuerySet)转换为可以轻松地表示成 JSON、XML 或其他媒体类型的格式(通常是 Python 原生的字典或列表)。
反序列化 (Deserialization): 将传入的低级表示(如 JSON 请求体)转换为复杂的 Python 数据类型(如模型实例),通常用于数据校验和保存。
DRF 的序列化器类似于 Django 的 Form
或 ModelForm
,但更侧重于处理 JSON 等数据格式。
创建一个产品模型:
在 products/models.py
中定义一个简单的 Product
模型。
“`python
products/models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=255)
description = models.TextField()
price = models.DecimalField(max_digits=10, decimal_places=2)
stock = models.IntegerField(default=0)
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)
def __str__(self):
return self.name
“`
执行数据库迁移:
bash
python manage.py makemigrations
python manage.py migrate
创建一个产品序列化器:
在 products
应用目录下创建一个 serializers.py
文件,并定义 ProductSerializer
。
“`python
products/serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.Serializer):
# 定义需要序列化/反序列化的字段
id = serializers.IntegerField(read_only=True) # read_only=True 表示该字段只用于序列化,不用于反序列化
name = serializers.CharField(max_length=255)
description = serializers.CharField()
price = serializers.DecimalField(max_digits=10, decimal_places=2)
stock = serializers.IntegerField()
created_at = serializers.DateTimeField(read_only=True)
updated_at = serializers.DateTimeField(read_only=True)
def create(self, validated_data):
"""
根据经过验证的数据,创建并返回一个新的 `Product` 实例。
"""
return Product.objects.create(**validated_data)
def update(self, instance, validated_data):
"""
根据经过验证的数据,更新并返回一个已有的 `Product` 实例。
"""
instance.name = validated_data.get('name', instance.name)
instance.description = validated_data.get('description', instance.description)
instance.price = validated_data.get('price', instance.price)
instance.stock = validated_data.get('stock', instance.stock)
instance.save()
return instance
“`
这个 Serializer
类需要手动定义每个字段以及 create()
和 update()
方法来处理对象的创建和更新。
使用 ModelSerializer (推荐):
DRF 提供了一个非常方便的 ModelSerializer
类,它可以根据 Django 模型自动生成字段和 create()
/ update()
方法。这是处理模型数据时最常用的方式。
修改 products/serializers.py
使用 ModelSerializer
:
“`python
products/serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = ‘all‘ # 或者指定字段列表: [‘id’, ‘name’, ‘price’, ‘stock’]
# read_only_fields = (‘created_at’, ‘updated_at’) # 如果使用 ‘all‘, 可以通过 read_only_fields 设置只读字段
“`
这样就大大简化了序列化器的定义!__all__
会包含模型中的所有字段(包括自动添加的 id)。如果你想排除某些字段,可以使用 exclude = [...]
。
DRF 核心组件:视图 (Views)
视图负责接收 HTTP 请求、处理业务逻辑(与模型和序列化器交互),并返回 HTTP 响应。DRF 提供了多种视图类型,从基本的 APIView
到功能强大的 ViewSet
。
1. APIView:
这是 DRF 提供的最基本的视图类,它继承自 Django 的 View
类,并添加了 DRF 特有的功能,如请求解析、响应渲染、认证、权限等。你可以像 Django 的 CBV 一样,为不同的 HTTP 方法 (GET, POST, PUT, DELETE) 定义对应的方法。
创建一个简单的产品列表和创建视图:
“`python
products/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Product
from .serializers import ProductSerializer
class ProductListCreateAPIView(APIView):
“””
产品列表和创建视图。
“””
def get(self, request, format=None):
“””
获取所有产品列表。
“””
products = Product.objects.all()
serializer = ProductSerializer(products, many=True) # many=True 表示序列化一个 QuerySet (列表)
return Response(serializer.data)
def post(self, request, format=None):
"""
创建新产品。
"""
serializer = ProductSerializer(data=request.data) # request.data 包含了请求体中的数据
if serializer.is_valid(): # 验证数据
serializer.save() # 调用 serializer 的 create() 或 update() 方法保存数据
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
“`
在 products/urls.py
中配置 URL:
“`python
products/urls.py
from django.urls import path
from .views import ProductListCreateAPIView
urlpatterns = [
path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’),
]
“`
在项目主 urls.py
(drf_project/urls.py
) 中包含应用的 URL:
“`python
drf_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘products.urls’)), # 将产品相关的 API 路由到 products 应用下
]
“`
现在,运行 python manage.py runserver
,访问 http://127.0.0.1:8000/api/products/
,你将看到一个漂亮的 DRF 提供的可浏览 API 界面(如果你没有数据,它会显示一个空的列表和 POST 表单)。你可以尝试通过这个界面或使用 Postman/curl 进行 GET 和 POST 请求。
2. GenericAPIView 和 Mixins:
APIView
虽然灵活,但对于常见的操作(如列表、创建、检索、更新、删除)仍需要手动编写大量重复的代码。DRF 提供了 GenericAPIView
,它继承自 APIView
并添加了一些常用属性(如 queryset
, serializer_class
, lookup_field
)和方法(如 get_object
, get_queryset
),用于简化代码。
更进一步,DRF 提供了一系列 Mixins(混入类),它们提供了具体的行为实现,如:
ListModelMixin
: 实现列表 (GET
) 操作。CreateModelMixin
: 实现创建 (POST
) 操作。RetrieveModelMixin
: 实现检索 (GET
by ID) 操作。UpdateModelMixin
: 实现更新 (PUT
/PATCH
by ID) 操作。DestroyModelMixin
: 实现删除 (DELETE
by ID) 操作。
通过继承 GenericAPIView
和一个或多个 Mixin,可以非常快速地构建常用视图。
修改 products/views.py
使用 Generic Views 和 Mixins:
“`python
products/views.py
… 导入不变
from rest_framework import generics
class ProductListCreateAPIView(generics.ListCreateAPIView):
“””
产品列表和创建视图 (使用 Generic Views)。
“””
queryset = Product.objects.all() # 指定查询集
serializer_class = ProductSerializer # 指定序列化器
class ProductRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
“””
产品详情、更新和删除视图 (使用 Generic Views)。
“””
queryset = Product.objects.all() # 指定查询集
serializer_class = ProductSerializer # 指定序列化器
lookup_field = ‘pk’ # 指定用于查找对象的 URL 参数名称,默认为 ‘pk’ (主键)
“`
修改 products/urls.py
以包含详情视图的路由:
“`python
products/urls.py
from django.urls import path
from .views import ProductListCreateAPIView # 替换
from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIView
urlpatterns = [
path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’),
path(‘products/
]
“`
现在,你有两个视图:一个处理 /api/products/
(GET for list, POST for create),另一个处理 /api/products/<id>/
(GET for retrieve, PUT/PATCH for update, DELETE for destroy)。代码量大大减少了,因为 Mixins 提供了大部分的实现。
3. ViewSets:
ViewSets 是 DRF 中更高级的概念,它将一组相关的视图逻辑(如列表、创建、检索、更新、删除)捆绑到一个类中,而不是像 Generic Views 那样分散到不同的类中。一个 ViewSet 不提供像 .get()
, .post()
这样的方法,而是提供像 .list()
, .create()
, .retrieve()
, .update()
, .partial_update()
, .destroy()
这样的方法。
ViewSets 的主要优势在于它们可以与 Routers(路由器)配合使用,自动生成 URL 配置,进一步简化了 URL 定义。
最常用的 ViewSet 是 ModelViewSet
,它继承了 GenericViewSet
和所有 Model Mixins (List, Create, Retrieve, Update, Destroy),因此它提供了完整的 CRUD (创建、检索、更新、删除) 功能。
修改 products/views.py
使用 ViewSet:
“`python
products/views.py
… 导入不变
from rest_framework import generics # 替换
from rest_framework import viewsets
class ProductViewSet(viewsets.ModelViewSet):
“””
产品 ViewSet,提供 list, create, retrieve, update, destroy 操作。
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
# lookup_field = ‘pk’ # ModelViewSet 默认使用 ‘pk’
“`
修改 products/urls.py
使用 Router:
DRF 提供了 Router 来自动生成 URL 配置。
“`python
products/urls.py
from django.urls import path # 替换
from django.urls import path, include # 需要 include
from .views import ProductListCreateAPIView, ProductRetrieveUpdateDestroyAPIView # 替换
from .views import ProductViewSet
from rest_framework.routers import DefaultRouter # 导入路由器
创建一个路由器实例
router = DefaultRouter()
注册 ViewSet 到路由器
参数1: URL 前缀 (不需要开头和结尾斜杠)
参数2: ViewSet 类
参数3: 可选,用于命名 URL 模式的基础名称 (通常是模型名的小写)
router.register(r’products’, ProductViewSet)
router.urls 会自动生成 URL 列表
urlpatterns = [
# path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’), # 替换
# path(‘products/
path(”, include(router.urls)), # 包含路由器生成的 URL
]
“`
在项目主 urls.py
(drf_project/urls.py
) 中包含应用的 URL 的方式不变。
现在,访问 /api/
路径(如果你的主 URL 配置是 /api/
),DRF 的可浏览 API 会显示路由器自动生成的 URL 列表,包括 /api/products/
(list, create) 和 /api/products/<id>/
(retrieve, update, destroy)。
使用 ModelViewSet
和 DefaultRouter
是构建典型 RESTful API 最快捷的方式,强烈推荐!
DRF 核心组件:请求 (Requests) 与响应 (Responses)
DRF 对 Django 原生的 HttpRequest
和 HttpResponse
进行了封装和增强。
- Request: DRF 的
Request
对象扩展了 Django 的HttpRequest
,最常用的属性是request.data
。request.data
可以处理多种媒体类型的请求内容(如 JSON, XML, 表单数据),并根据请求的Content-Type
自动解析。这意味着你不需要手动检查request.method
或request.body
并解析 JSON。 - Response: DRF 的
Response
对象继承自TemplateResponse
,它接收 Python 原生的数据(如字典、列表)作为其第一个参数,并负责将其渲染成客户端期望的格式(如 JSON)。它根据请求的Accept
头部信息选择合适的渲染器。这使得你可以直接返回 Python 数据,而无需手动将数据转换为 JSON 字符串。
这是 DRF 易用性的重要体现:在视图中处理的都是 Python 数据,DRF 负责底层的格式转换。
可浏览 API (Browsable API)
正如你在上面的例子中看到的,DRF 提供了一个非常实用的功能:可浏览 API。当你使用浏览器访问由 DRF View 或 ViewSet 支持的 URL 时,DRF 会渲染一个 HTML 页面,该页面展示了 API 的可用端点、允许的 HTTP 方法、序列化器的字段、以及一个用于发送 POST/PUT/PATCH 请求的表单。
这个功能对于开发、调试和测试 API 极其有用,它让你无需其他工具就能直观地与 API 交互。
DRF 核心组件:认证 (Authentication) 与权限 (Permissions)
构建实际的 API,安全性是必不可少的。你需要知道请求是谁发起的(认证),以及该用户是否有权执行请求的操作(权限)。
- 认证 (Authentication): 验证请求的凭证(如用户名/密码、Token、Session ID),从而确定是哪个用户发起的请求。DRF 提供了多种认证类,如
SessionAuthentication
(用于与 Django Session 配合,适合 Web 应用)、TokenAuthentication
(基于 Token 的简单认证)、BasicAuthentication
等。你也可以实现自定义的认证类。 - 权限 (Permissions): 验证通过认证的用户是否有执行特定操作的权限。DRF 提供了多种权限类,如
IsAuthenticated
(要求用户必须认证)、IsAdminUser
(要求用户必须是管理员)、IsAuthenticatedOrReadOnly
(认证用户有读写权限,匿名用户只有读权限)。你也可以实现自定义的权限类,例如基于对象的权限。
你可以在视图或 ViewSet 中通过 authentication_classes
和 permission_classes
属性来指定使用的认证和权限类。
“`python
products/views.py (添加认证和权限示例)
… 导入不变
from rest_framework.permissions import IsAuthenticatedOrReadOnly # 导入权限类
from rest_framework.authentication import TokenAuthentication # 导入认证类 (如果使用 Token 认证)
class ProductViewSet(viewsets.ModelViewSet):
“””
产品 ViewSet,添加认证和权限。
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
# lookup_field = ‘pk’ # ModelViewSet 默认使用 ‘pk’
# authentication_classes = [TokenAuthentication] # 如果使用 Token 认证,取消注释
permission_classes = [IsAuthenticatedOrReadOnly] # 设置权限类
“`
将 IsAuthenticatedOrReadOnly
应用到 ProductViewSet
意味着:未认证的用户只能通过 GET 请求查看产品列表和详情;认证用户可以执行所有操作 (GET, POST, PUT, PATCH, DELETE)。
注意: 使用 TokenAuthentication
需要在 settings.py
中配置并运行迁移,还需要生成 Token。这是另一个可以深入学习的话题,本文不再展开,但知道它们的存在和如何应用于视图是很重要的。
其他重要组件:分页 (Pagination) 与过滤 (Filtering)
对于包含大量数据的 API,一次性返回所有数据是不现实的。DRF 提供了分页功能,允许你限制返回结果的数量,并提供下一页/上一页的链接。
- Pagination: 常见的类型有
PageNumberPagination
(基于页码) 和LimitOffsetPagination
(基于偏移量和限制数量)。你可以在settings.py
中设置全局默认分页类,也可以在视图中通过pagination_class
属性覆盖。
“`python
drf_project/settings.py (全局设置分页)
REST_FRAMEWORK = {
‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
‘PAGE_SIZE’: 10 # 每页项目数
}
“`
设置后,访问 /api/products/
将自动分页,你可以通过 /api/products/?page=2
或 /api/products/?limit=20&offset=20
(取决于分页类) 来访问不同页。
- Filtering: 允许客户端通过 URL 参数对结果集进行过滤。DRF 提供了一个独立的包
django-filter
与其集成。安装并配置后,你可以通过filter_backends
属性在视图中启用过滤。
bash
pip install django-filter
“`python
drf_project/settings.py (注册 django-filter)
INSTALLED_APPS = [
# … 其他应用
‘django_filters’, # 注册 django-filter
‘rest_framework’,
# …
]
REST_FRAMEWORK = {
# … 分页设置
‘DEFAULT_FILTER_BACKENDS’: [‘django_filters.rest_framework.DjangoFilterBackend’] # 默认过滤后端
}
“`
“`python
products/views.py (在 ViewSet 中使用过滤)
… 导入不变
from django_filters.rest_framework import DjangoFilterBackend # 导入过滤后端
class ProductViewSet(viewsets.ModelViewSet):
# … queryset, serializer_class, permission_classes
filter_backends = [DjangoFilterBackend] # 启用过滤后端
filterset_fields = ['name', 'price', 'stock'] # 指定允许过滤的字段
“`
现在,你可以通过 /api/products/?name=Example&price=10.00
来过滤产品。
总结与下一步
恭喜你!通过上面的步骤,你已经从零开始,理解了 DRF 的核心组件,并通过一个产品 API 的例子,实践了序列化器、各种视图类型(特别是 ViewSet)、请求/响应处理、URL 路由(特别是 Router),并了解了认证、权限、分页和过滤的基本概念。
你已经掌握了构建 RESTful API 的基本骨架。然而,DRF 的功能远不止于此。为了更深入地掌握 DRF,你可以进一步学习以下内容:
- 深入理解 Serializers: 学习如何处理嵌套序列化、自定义字段、验证器 (
Validators
)。 - 高级视图技术: 探索
GenericViewSet
的用法,如何使用自定义 Mixins。 - 认证与权限实战: 学习如何实现
TokenAuthentication
、JWT 认证,以及如何编写自定义的权限类。 - 测试 API: 学习如何使用 Django 的
TestCase
或 DRF 提供的APITestCase
来编写 API 测试用例。 - 版本控制 (Versioning): 当 API 发生变化时,如何优雅地处理不同版本的 API。
- 限流 (Throttling): 如何限制用户或客户端的请求频率。
- 自定义组件: 如何编写自定义的解析器 (Parsers)、渲染器 (Renderers)、字段 (Fields)、序列化器 (Serializers) 或 ViewSets。
- 文档生成: 使用工具如 Swagger/OpenAPI (drf-yasg, drf-spectacular) 为你的 API 生成交互式文档。
DRF 官方文档是最好的学习资源。它非常详细且更新及时。通过不断实践和查阅文档,你将能够充分发挥 DRF 的强大能力,构建出高效、健壮且易于维护的 Web API。
记住,最好的学习方法是动手实践。尝试在你自己的 Django 项目中使用 DRF,构建不同类型的 API,解决遇到的问题,这将是你掌握 DRF 最快的方式。
祝你在 DRF 的学习旅程中一切顺利!