一文读懂 Django REST Framework (DRF)
在现代Web开发中,构建强大的、可供不同客户端(如Web浏览器、移动应用、第三方服务)消费的API已成为核心需求。Django以其”快速开发,避免重复造轮子”的理念闻名,而Django REST Framework (DRF)正是Django生态系统中最受欢迎、功能最强大的工具,用于构建RESTful API。
本文将带你深入了解DRF,从其基本概念到核心组件,再到实际应用,力求让你“一文读懂”DRF的精髓。
1. 什么是 RESTful API?为什么选择 DRF?
在深入DRF之前,我们先简单回顾一下RESTful API的概念。REST(Representational State Transfer)是一种架构风格,用于设计网络应用程序接口。遵循RESTful原则的API通常具有以下特点:
- 无状态 (Stateless): 服务器不存储客户端的状态信息。
- 客户端-服务器分离 (Client-Server): 客户端和服务器的职责分离。
- 统一接口 (Uniform Interface): 使用标准的HTTP方法(GET, POST, PUT, PATCH, DELETE)操作资源。
- 资源 (Resources): 数据被抽象为资源,每个资源都有一个URI(统一资源标识符)。
- 表现形式 (Representational): 资源通过某种表现形式(如JSON, XML)在客户端和服务器之间传输。
- 分层系统 (Layered System): 客户端无法感知它是否直接连接到最终服务器,或者中间是否有代理、网关等。
为什么选择 DRF?
虽然你可以使用Django自身的功能来构建返回JSON或XML的视图,但这会非常繁琐。你需要手动处理:
- 解析请求体(JSON, XML等)。
- 验证输入数据。
- 将Python对象序列化成可传输的格式(JSON, XML等)。
- 处理认证和权限。
- 实现分页、过滤、搜索等功能。
- 生成API文档。
DRF正是为了解决这些痛点而生。它提供了一套强大而灵活的工具集,极大地简化了构建Web API的过程:
- 序列化器 (Serializers): 轻松地将Django模型或其他数据源转换为API响应所需的格式,并处理反序列化和数据验证。
- 视图 (Views): 提供基于类的视图(Class-Based Views, CBVs)和通用视图(Generic Views),极大地减少了编写视图逻辑所需的代码。
- 认证与权限 (Authentication & Permissions): 内置多种认证和权限方案,轻松控制谁可以访问你的API以及他们能做什么。
- 分页、过滤与搜索 (Pagination, Filtering & Searching): 提供简单的配置来实现这些常见的API功能。
- 可浏览的API (Browsable API): DRF自带一个美观的、可用于测试和调试API的Web界面。
- 灵活的渲染器与解析器 (Renderers & Parsers): 支持多种数据格式(JSON, XML, HTML等),并可轻松扩展。
- 强大的文档生成 (Documentation): 易于集成API文档生成工具。
总而言之,DRF是构建高效、可维护、功能丰富的Django API的首选框架。
2. 安装与基本配置
开始使用DRF非常简单。
安装:
bash
pip install djangorestframework
配置:
将 'rest_framework'
添加到你的Django项目的 settings.py
文件中的 INSTALLED_APPS
列表中:
“`python
settings.py
INSTALLED_APPS = [
# … 其他应用
‘rest_framework’,
# 如果需要Token认证,还需要这个
‘rest_framework.authtoken’,
]
“`
这样,DRF就集成到了你的Django项目中。
3. 核心概念详解
理解DRF的核心概念是掌握它的关键。它们包括:
3.1 Serializers (序列化器)
序列化器是DRF中最核心也是最重要的组件之一。它的主要职责有两个:
- 序列化 (Serialization): 将复杂的Python数据类型(如Django模型实例、查询集)转换为可传输的格式(如JSON、XML)。
- 反序列化 (Deserialization): 将接收到的可传输格式数据(如JSON请求体)转换回Python数据类型,并对数据进行验证。
这就像API的输入输出转换器和数据校验器。
基本使用:
我们通常使用 rest_framework.serializers.Serializer
或 rest_framework.serializers.ModelSerializer
。
Serializer
: 用于处理非模型数据,或者需要完全自定义字段和验证逻辑时。ModelSerializer
: 用于直接与Django模型关联。它可以自动生成字段和基本验证,大大简化代码。这是最常用的方式。
示例:使用 ModelSerializer
假设我们有一个简单的模型:
“`python
models.py
from django.db import models
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=10, decimal_places=2)
in_stock = models.BooleanField(default=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
“`
创建一个对应的序列化器:
“`python
serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
class Meta:
model = Product
fields = [‘id’, ‘name’, ‘price’, ‘in_stock’, ‘created_at’]
# 或者使用 exclude = [‘some_field’] 排除特定字段
# 或者使用 fields = ‘all‘ 包含所有字段 (不推荐,不够明确)
# read_only_fields = [‘created_at’] # 这些字段只用于输出,不用于输入验证
“`
序列化数据:
“`python
在 Django shell 或视图中
from .models import Product
from .serializers import ProductSerializer
序列化单个对象
product = Product.objects.first()
serializer = ProductSerializer(product)
print(serializer.data) # 输出一个字典,可以转换为 JSON
序列化查询集 (多个对象)
queryset = Product.objects.all()
serializer = ProductSerializer(queryset, many=True) # many=True 是关键
print(serializer.data) # 输出一个字典列表,可以转换为 JSON 数组
“`
反序列化与验证:
当接收到客户端发送的数据(通常是PUT/POST/PATCH请求的请求体)时,我们使用序列化器进行反序列化和验证。
“`python
假设 request.data 包含了客户端发送的数据,比如 {“name”: “New Product”, “price”: 199.99, “in_stock”: true}
from .serializers import ProductSerializer
serializer = ProductSerializer(data=request.data) # 将输入数据传给 data 参数
if serializer.is_valid(): # 执行验证
# 数据有效
product_instance = serializer.save() # 调用 serializer.save() 创建或更新对象
# product_instance 就是创建或更新后的 Product 模型实例
print(“数据有效,保存成功!”)
print(product_instance)
else:
# 数据无效
print(serializer.errors) # 包含验证失败的错误信息字典
“`
serializer.save()
方法会自动调用 create()
或 update()
方法:
- 如果序列化器是用
data
参数初始化的(用于创建),它会调用serializer.create(validated_data)
。 - 如果序列化器是用一个模型实例和一个
data
参数初始化的(用于更新),它会调用serializer.update(instance, validated_data)
。
你可以在序列化器中重写 create()
和 update()
方法来添加自定义保存逻辑。
自定义字段和验证:
可以在序列化器中显式定义字段,这允许你定制字段的行为、添加只读字段、写字段(Write-only fields)、计算字段等。
“`python
serializers.py
from rest_framework import serializers
from .models import Product
class ProductSerializer(serializers.ModelSerializer):
# 添加一个只读的计算字段
is_expensive = serializers.SerializerMethodField()
# 定义一个写字段,只用于输入,不用于输出
category_name = serializers.CharField(write_only=True)
class Meta:
model = Product
fields = ['id', 'name', 'price', 'in_stock', 'created_at', 'is_expensive', 'category_name']
read_only_fields = ['created_at'] # 也可以在这里设置只读字段
def get_is_expensive(self, obj):
# obj 是 Product 模型实例
return obj.price > 100.00
# 对象级别的验证
def validate(self, data):
# 假设我们不允许价格为负数
if data.get('price') < 0:
raise serializers.ValidationError({"price": "价格不能为负数。"})
return data
# 字段级别的验证
def validate_name(self, value):
# 假设产品名称不能包含“测试”二字
if "测试" in value:
raise serializers.ValidationError("产品名称不能包含‘测试’。")
return value
# 重写 create 方法(示例:假设 category_name 用于查找或创建 Category 关联)
def create(self, validated_data):
category_name = validated_data.pop('category_name', None)
# 这里可以根据 category_name 处理 Category 关联逻辑
product = Product.objects.create(**validated_data)
return product
“`
序列化器是DRF数据处理的核心,掌握它至关重要。
3.2 Views (视图)
DRF的视图负责处理请求并返回响应。它们与Django视图类似,但提供了更多API特有的功能,如自动处理认证、权限、内容协商等。
DRF提供了几种不同层次的视图抽象:
APIView
: DRF最基础的视图类,继承自Django的View
。它提供了DRF的核心功能,如.get()
,.post()
等方法,并会自动处理DRF的Request
和Response
对象,应用认证、权限、限流等策略。当你需要完全自定义视图逻辑时使用它。- Generic APIViews (通用API视图): DRF提供了一系列预定义的通用视图类,用于处理常见的模型操作,如列表、详情、创建、更新、删除。它们通过结合 Mixins (混入类) 和
GenericAPIView
实现。这极大地减少了代码量。ListAPIView
: 只读列表。RetrieveAPIView
: 只读详情。CreateAPIView
: 只写创建。UpdateAPIView
: 只写更新。DestroyAPIView
: 只写删除。ListCreateAPIView
: 列表和创建。RetrieveUpdateDestroyAPIView
: 详情、更新和删除。RetrieveUpdateAPIView
: 详情和更新。RetrieveDestroyAPIView
: 详情和删除。
使用它们时,你通常只需设置queryset
和serializer_class
属性。
- ViewSets (视图集): DRF的最高层次抽象。它将一组相关的视图逻辑(如列表、详情、创建、更新、删除)组合到一个类中,而不是像常规视图那样分散到多个URL。ViewSets通常与 Routers 配合使用,可以自动生成URL配置。
ViewSet
: 基础视图集,需要自己实现.list()
,.retrieve()
,.create()
等方法。GenericViewSet
: 结合了GenericAPIView
的功能,可以与Mixins配合使用,但没有默认提供list
,retrieve
等方法,需要手动添加Mixins。ModelViewSet
: 继承自GenericViewSet
并包含了所有标准的 Mixins (ListModelMixin
,RetrieveModelMixin
,CreateModelMixin
,UpdateModelMixin
,DestroyModelMixin
)。它是处理Django模型CRUD操作最快捷的方式。你只需设置queryset
和serializer_class
。
示例:使用不同类型的视图
APIView
示例:
“`python
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 ProductListAPIView(APIView):
“””
List all products or create a new product.
“””
def get(self, request, format=None):
products = Product.objects.all()
serializer = ProductSerializer(products, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ProductSerializer(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)
URL 配置 (urls.py)
from django.urls import path
from .views import ProductListAPIView
urlpatterns = [
path(‘products/’, ProductListAPIView.as_view(), name=’product-list’),
]
“`
Generic APIView 示例 (ListCreateAPIView
):
“`python
views.py
from rest_framework import generics
from .models import Product
from .serializers import ProductSerializer
class ProductListCreateAPIView(generics.ListCreateAPIView):
“””
List all products or create a new product (using Generic View).
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
URL 配置 (urls.py)
from django.urls import path
from .views import ProductListCreateAPIView
urlpatterns = [
path(‘products/’, ProductListCreateAPIView.as_view(), name=’product-list-create’),
]
“`
可以看到使用 Generic Views 代码量大大减少。
ModelViewSet 示例:
“`python
views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
“””
A simple ViewSet for viewing and editing products.
Provides: list, retrieve, create, update, partial_update, destroy actions.
“””
queryset = Product.objects.all()
serializer_class = ProductSerializer
URL 配置通常使用 Routers (详见下文)
“`
选择哪种视图取决于你的需求。对于简单的CRUD操作,ModelViewSet
是最快的;对于组合操作或需要自定义逻辑较多时,Generic APIViews
方便;当需要完全控制请求/响应流程时,使用 APIView
。
3.3 URLs and Routers (URLs 和 路由)
将视图映射到URL是构建API的下一步。对于基于 APIView
或 Generic Views 的视图,你使用标准的Django urls.py
配置:
“`python
urls.py
from django.urls import path
from .views import ProductListAPIView, ProductDetailAPIView # 假设你写了详情视图
urlpatterns = [
path(‘products/’, ProductListAPIView.as_view(), name=’product-list’),
# path(‘products/
]
“`
对于 ViewSets,DRF提供了一个强大的工具 Routers (路由),它可以根据 ViewSet 自动生成标准的URL配置(列表、详情等)。
示例:使用 DefaultRouter
“`python
urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet # 假设你定义了 ProductViewSet
创建一个路由器实例
router = DefaultRouter()
注册 ViewSet
第一个参数是 URL 前缀,第二个参数是 ViewSet 类,第三个参数是可选的 base_name (用于生成 URL 名称)
router.register(r’products’, ProductViewSet, basename=’product’)
urlpatterns 现在包含了由路由器自动生成的 URL
urlpatterns = [
path(”, include(router.urls)), # 包含路由器生成的 URL
# 你也可以在这里添加其他的非 ViewSet 的 URL
# path(‘some-custom-path/’, some_custom_view.as_view(), name=’custom-view’),
]
“`
使用 DefaultRouter
注册 ProductViewSet
后,它会自动生成如下URL模式(假设URL前缀是 /
):
/products/
(GET: list, POST: create)/products/{pk}/
(GET: retrieve, PUT: update, PATCH: partial_update, DELETE: destroy)
DefaultRouter
还提供了可浏览API的入口点和格式后缀模式。如果你不需要这些,可以使用 SimpleRouter
。
Router 是 ViewSets 的完美搭档,它们共同极大地提高了API开发效率。
3.4 Requests and Responses (请求和响应)
DRF 引入了增强型的 Request
和 Response
对象:
Request
: DRF的Request
对象继承自Django的HttpRequest
,但提供了更灵活的解析功能。request.data
: 包含了解析后的请求体内容,不论是POST、PUT、PATCH请求,也不论内容是JSON、XML还是表单数据,DRF都会根据请求头的Content-Type
使用合适的解析器进行解析。request.query_params
: Django原生的request.GET
,用于获取URL中的查询参数。request.parser_classes
: 控制请求使用哪些解析器。
Response
: DRF的Response
对象继承自Django的HttpResponse
,但它接受未渲染的Python数据(如字典、列表)作为参数,并使用内容协商机制根据客户端请求头 (Accept
头部) 和配置的渲染器自动渲染为合适的格式(默认为JSON)。你还可以方便地设置HTTP状态码。
“`python
示例:在 APIView 中使用 Request 和 Response
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class MyView(APIView):
def post(self, request, format=None):
# 获取解析后的请求体数据
data = request.data
print(data)
# 处理数据...
# 返回响应,DRF会自动将其渲染为 JSON (或其他格式)
return Response({"message": "Data received", "your_data": data}, status=status.HTTP_201_CREATED)
“`
3.5 Authentication (认证)
认证是确定谁发出了请求的过程。DRF提供了多种认证方案:
SessionAuthentication
: 使用Django的标准session/cookie认证。适合与基于session的Web界面结合使用。BasicAuthentication
: 使用HTTP Basic认证,将用户名和密码 Base64 编码后放在Authorization
头部。不安全,通常只用于测试或内部服务。TokenAuthentication
: 基于Token的认证。用户登录后获取一个Token,后续请求在Authorization
头部携带此Token (Token <the_token>
) 进行认证。适合移动应用或第三方服务调用。需要将rest_framework.authtoken
加入INSTALLED_APPS
并运行迁移。RemoteUserAuthentication
: 使用Web服务器提供的认证信息。- OAuth1/OAuth2 等第三方认证库也可以与DRF集成。
配置:
可以在 settings.py
中全局配置默认认证类:
“`python
settings.py
REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.TokenAuthentication’,
‘rest_framework.authentication.SessionAuthentication’, # 可以同时配置多种
],
# … 其他配置
}
“`
也可以在单个视图或 ViewSet 中配置:
“`python
views.py
from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated # 通常与权限一起使用
class SecuredView(APIView):
authentication_classes = [TokenAuthentication] # 仅使用Token认证
permission_classes = [IsAuthenticated] # 要求用户已认证
def get(self, request, format=None):
# request.user 将是被认证的用户实例 (如果认证成功)
return Response({"message": f"Hello, {request.user.username}!"})
“`
当认证成功后,request.user
会被设置为对应的用户实例,request.auth
会被设置为认证凭证(如Token实例)。
3.6 Permissions (权限)
权限是确定已认证用户是否有权执行某个操作的过程。认证只告诉你“是谁”,权限才决定“能做什么”。
DRF提供了多种权限类:
AllowAny
: 允许任何用户(包括未认证用户)访问。这是默认设置。IsAuthenticated
: 只允许已认证用户访问。IsAdminUser
: 只允许Django管理员用户访问。IsAuthenticatedOrReadOnly
: 允许已认证用户进行写操作(POST, PUT, PATCH, DELETE),未认证用户只能进行读操作(GET, HEAD, OPTIONS)。DjangoModelPermissions
: 基于Django的django.contrib.auth
模型权限系统。DjangoObjectPermissions
: 基于Django的对象级别权限系统(如 django-guardian)。
配置:
可以在 settings.py
中全局配置默认权限类:
“`python
settings.py
REST_FRAMEWORK = {
# … 其他配置
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticated’, # 默认要求所有API都需要认证
]
}
“`
也可以在单个视图或 ViewSet 中配置:
“`python
views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAdminUser
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# 配置视图集的权限
permission_classes = [IsAuthenticatedOrReadOnly] # 列表和详情允许任何人,创建、更新、删除只允许认证用户
# 对于特定的 action 可以覆盖权限
def get_permissions(self):
if self.action == 'create':
# 只有管理员才能创建产品
return [IsAdminUser()]
return super().get_permissions() # 其他操作使用 IsAuthenticatedOrReadOnly
“`
自定义权限:
可以继承 rest_framework.permissions.BasePermission
类并实现 has_permission(self, request, view)
(对象级别,检查用户是否有权限访问 这个视图 或 这类对象) 和 has_object_permission(self, request, view, obj)
(对象级别,检查用户是否有权限对 这个特定对象 执行操作)。
“`python
permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
“””
Custom permission to only allow owners of an object to edit it.
“””
def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True
# Write permissions are only allowed to the owner of the snippet.
# Assuming the model instance has an 'owner' attribute.
return obj.owner == request.user
在 views.py 中使用
class SomeModelViewSet(viewsets.ModelViewSet):
queryset = SomeModel.objects.all()
serializer_class = SomeModelSerializer
permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly] # 注意顺序,通常先检查通用权限,再检查对象权限
“`
3.7 Pagination (分页)
当数据集很大时,一次性返回所有数据会导致性能问题和网络延迟。分页可以将结果集分割成小块返回。
DRF内置了三种分页器:
PageNumberPagination
: 基于页码的分页。客户端通过查询参数?page=N
和?page_size=M
请求特定页码和每页数量。LimitOffsetPagination
: 基于偏移量和数量的分页。客户端通过?limit=M
和?offset=N
请求。类似于SQL的LIMIT
和OFFSET
。CursorPagination
: 基于游标的分页。更适合处理大型、不断变化的数据集,因为它基于数据中的某个固定点(游标)获取下一批数据,避免了传统分页可能出现的重复或跳过数据问题。它要求数据集有一个固定的、唯一的排序字段。
配置:
可以在 settings.py
中全局配置默认分页样式:
“`python
settings.py
REST_FRAMEWORK = {
# … 其他配置
‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
‘PAGE_SIZE’: 10, # 默认每页数量
}
“`
也可以在单个视图或 ViewSet 中配置:
“`python
views.py
from rest_framework import viewsets
from rest_framework.pagination import LimitOffsetPagination
… (其他导入)
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
pagination_class = LimitOffsetPagination # 只对此视图集应用 LimitOffsetPagination
# 对于 LimitOffsetPagination,可以通过 settings.py 或 view/viewset 设置 limit_query_param, offset_query_param 等
# limit_query_param = ‘count’ # 示例:客户端用 ?count=…
# offset_query_param = ‘start’ # 示例:客户端用 ?start=…
“`
3.8 Filtering and Searching (过滤和搜索)
允许客户端通过URL查询参数过滤或搜索结果集是API的常见需求。DRF通过过滤器后端(Filter Backends)实现这些功能。
常用的过滤器后端:
rest_framework.filters.DjangoFilterBackend
: 最常用的过滤器后端,通常与第三方库django-filter
结合使用,实现强大的字段过滤。rest_framework.filters.SearchFilter
: 实现基于字段的模糊搜索。rest_framework.filters.OrderingFilter
: 实现结果集的排序。
安装 django-filter
(如果使用 DjangoFilterBackend
):
bash
pip install django-filter
添加到 settings.py
:
“`python
settings.py
INSTALLED_APPS = [
# …
‘django_filters’,
# …
]
如果全局配置 DjangoFilterBackend
REST_FRAMEWORK = {
# …
‘DEFAULT_FILTER_BACKENDS’: [‘django_filters.rest_framework.DjangoFilterBackend’],
}
“`
使用示例:
“`python
views.py
from rest_framework import viewsets
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend # 导入 DjangoFilterBackend
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# 配置过滤器后端
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
# 配置 DjangoFilterBackend 允许过滤的字段
filterset_fields = [‘category’, ‘in_stock’] # 假设 Product 模型有 category 外键或字段
# 配置 SearchFilter 允许搜索的字段 (使用 __ 操作符指定搜索方式)
search_fields = [‘name’, ‘description’] # 搜索 name 和 description 字段 (默认为 __icontains)
# 配置 OrderingFilter 允许排序的字段
ordering_fields = [‘price’, ‘created_at’] # 允许按 price 和 created_at 排序
# 默认排序字段
ordering = [‘-created_at’] # 默认按创建时间降序排列
“`
有了这些配置,客户端就可以这样请求数据:
/products/?category=electronics&in_stock=true
(过滤)/products/?search=laptop
(搜索)/products/?ordering=price
(按价格升序排序)/products/?ordering=-price
(按价格降序排序)/products/?category=electronics&search=phone&ordering=-price
(组合使用)
3.9 Versioning (版本控制)
API通常会随着时间演进,为了不破坏现有客户端,需要进行版本控制。DRF提供了多种版本控制方案:
URLPathVersioning
: 将版本号包含在URL路径中 (e.g.,/v1/products/
)。NamespaceVersioning
: 基于URL命名空间的版本控制。QueryParameterVersioning
: 将版本号作为查询参数 (e.g.,/products/?version=v1
)。HostNameVersioning
: 将版本号作为主机名的一部分 (e.g.,v1.api.example.com/products/
)。AcceptHeaderVersioning
: 将版本号包含在Accept
头部中 (e.g.,Accept: application/json; version=v1
)。
配置:
“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_VERSIONING_CLASS’: ‘rest_framework.versioning.URLPathVersioning’,
‘DEFAULT_VERSION’: ‘v1’, # 默认版本
‘ALLOWED_VERSIONS’: [‘v1’, ‘v2’], # 允许的版本
‘VERSION_PARAM’: ‘version’, # 在 URL 中用于表示版本的参数名
}
urls.py (使用 URLPathVersioning 示例)
from django.urls import path, include, re_path
from rest_framework.routers import DefaultRouter
from .views import ProductViewSet # v1
from .views_v2 import ProductViewSet as ProductViewSetV2 # v2
router_v1 = DefaultRouter()
router_v1.register(r’products’, ProductViewSet, basename=’product-v1′)
router_v2 = DefaultRouter()
router_v2.register(r’products’, ProductViewSetV2, basename=’product-v2′)
urlpatterns = [
re_path(r’^v(?P
# 或者为 v2 单独定义 URL
# re_path(r’^v(?P
# 更简单的办法通常是在 viewset/serializer 里根据 request.version 判断版本
# 或者为不同版本创建完全独立的 urls.py 文件
]
“`
选择合适的版本控制策略取决于你的项目需求和偏好。
3.10 Throttling (限流)
限流用于控制客户端在一定时间内可以向API发出的请求数量,以防止滥用和过载。
DRF提供了几种限流策略:
AnonRateThrottle
: 限制未经认证用户的请求速率。UserRateThrottle
: 限制已认证用户的请求速率。ScopedRateThrottle
: 限制特定作用域(如某个API endpoint)的请求速率。
配置:
可以在 settings.py
中全局配置:
“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_THROTTLE_CLASSES’: [
‘rest_framework.throttling.AnonRateThrottle’,
‘rest_framework.throttling.UserRateThrottle’
],
‘DEFAULT_THROTTLE_RATES’: {
‘anon’: ‘100/day’, # 匿名用户每天最多100次请求
‘user’: ‘1000/day’, # 认证用户每天最多1000次请求
‘ burst’: ’60/min’, # 示例:自定义作用域限流
‘sustained’: ‘1000/day’, # 示例:自定义作用域限流
}
}
“`
也可以在视图或 ViewSet 中配置:
“`python
views.py
from rest_framework.views import APIView
from rest_framework.throttling import ScopedRateThrottle
class ProductListView(APIView):
# … (其他属性)
throttle_classes = [ScopedRateThrottle]
throttle_scope = ‘products_list’ # 定义作用域名称
settings.py 中配置这个作用域的限流速率
REST_FRAMEWORK = {
…
‘DEFAULT_THROTTLE_RATES’: {
…
‘products_list’: ’60/minute’, # 每分钟最多60次请求
}
}
“`
3.11 Renderers and Parsers (渲染器和解析器)
- Renderers (渲染器): 控制API响应如何被渲染成特定媒体类型的内容(如JSON、HTML)。DRF内置了
JSONRenderer
,BrowsableAPIRenderer
,StaticHTMLRenderer
等。 - Parsers (解析器): 控制DRF如何解析请求体的内容,将其转换为
request.data
。DRF内置了JSONParser
,FormParser
,MultiPartParser
等。
DRF使用 内容协商 (Content Negotiation) 机制,根据客户端请求头 Accept
(对于渲染器)或 Content-Type
(对于解析器)来选择合适的类进行处理。
配置:
可以在 settings.py
中全局配置默认的渲染器和解析器:
“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_RENDERER_CLASSES’: [
‘rest_framework.renderers.JSONRenderer’,
‘rest_framework.renderers.BrowsableAPIRenderer’, # 通常在开发环境中开启
],
‘DEFAULT_PARSER_CLASSES’: [
‘rest_framework.parsers.JSONParser’,
‘rest_framework.parsers.FormParser’, # 处理表单数据
‘rest_framework.parsers.MultiPartParser’ # 处理文件上传
]
}
“`
也可以在视图或 ViewSet 中配置:
“`python
views.py
from rest_framework.views import APIView
from rest_framework.renderers import JSONRenderer
from rest_framework.parsers import JSONParser
class MyJsonView(APIView):
renderer_classes = [JSONRenderer] # 只渲染为 JSON
parser_classes = [JSONParser] # 只解析 JSON 请求体
# ...
“`
BrowsableAPIRenderer
是DRF非常酷炫的功能,它在浏览器访问API时提供了一个交互式的HTML界面,方便测试和调试。在生产环境中,通常会移除它,只保留 JSONRenderer
等。
4. 整合示例:构建一个简单的产品 API
我们将前面介绍的核心概念整合起来,构建一个简单的产品API。
1. 创建应用和模型:
bash
python manage.py startapp products_api
在 products_api/models.py
中定义 Product 模型 (如上文所示)。
添加到 INSTALLED_APPS
并运行迁移。
2. 创建 Serializer:
在 products_api/serializers.py
中定义 ProductSerializer
(如上文所示)。
3. 创建 ViewSet:
在 products_api/views.py
中定义 ProductViewSet
(使用 ModelViewSet
,如上文所示)。
“`python
products_api/views.py
from rest_framework import viewsets
from .models import Product
from .serializers import ProductSerializer
class ProductViewSet(viewsets.ModelViewSet):
queryset = Product.objects.all()
serializer_class = ProductSerializer
# 添加一些常用的功能
filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]
filterset_fields = [‘in_stock’]
search_fields = [‘name’]
ordering_fields = [‘price’, ‘created_at’]
# pagination_class = PageNumberPagination # 如果需要分页,在此或 settings 中配置
# permission_classes = [IsAuthenticatedOrReadOnly] # 如果需要权限控制
``
django-filter
*(注意:这里假设已经安装并配置了和
rest_framework.filters`)*
4. 配置 URL 使用 Router:
在项目主 urls.py
中配置路由:
“`python
project/urls.py
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from products_api.views import ProductViewSet # 导入 ViewSet
router = DefaultRouter()
router.register(r’products’, ProductViewSet) # 注册产品 ViewSet
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(router.urls)), # 将 DRF 路由包含在 /api/ 路径下
# path(‘api-auth/’, include(‘rest_framework.urls’)), # 可选:为可浏览API添加登录/注销功能
]
“`
5. 配置 settings.py (可选):
根据需要配置全局认证、权限、分页、限流等。
“`python
settings.py
REST_FRAMEWORK = {
# Use Django’s standard django.contrib.auth
permissions,
# or allow read-only access for unauthenticated users.
# ‘DEFAULT_PERMISSION_CLASSES’: [
# ‘rest_framework.permissions.IsAuthenticatedOrReadOnly’
# ],
# ‘DEFAULT_AUTHENTICATION_CLASSES’: [
# ‘rest_framework.authentication.SessionAuthentication’,
# ‘rest_framework.authentication.TokenAuthentication’,
# ],
# ‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
# ‘PAGE_SIZE’: 10,
# ‘DEFAULT_FILTER_BACKENDS’: [
# ‘django_filters.rest_framework.DjangoFilterBackend’,
# ‘rest_framework.filters.SearchFilter’,
# ‘rest_framework.filters.OrderingFilter’,
# ],
# ‘DEFAULT_THROTTLE_CLASSES’: [
# ‘rest_framework.throttling.AnonRateThrottle’,
# ‘rest_framework.throttling.UserRateThrottle’
# ],
# ‘DEFAULT_THROTTLE_RATES’: {
# ‘anon’: ‘100/day’,
# ‘user’: ‘1000/day’
# }
}
“`
6. 运行服务器并测试:
bash
python manage.py runserver
现在你可以通过浏览器访问 http://127.0.0.1:8000/api/products/
,如果开启了 BrowsableAPIRenderer
,你将看到一个漂亮的可浏览API界面,可以进行列表、创建、查看、更新、删除等操作。
你也可以使用 curl
或 Postman 等工具测试:
GET http://127.0.0.1:8000/api/products/
(获取产品列表)POST http://127.0.0.1:8000/api/products/ -H "Content-Type: application/json" -d '{"name": "Test Product", "price": 50.00}'
(创建产品)GET http://127.0.0.1:8000/api/products/1/
(获取ID为1的产品详情)PUT http://127.0.0.1:8000/api/products/1/ -H "Content-Type: application/json" -d '{"name": "Updated Product", "price": 55.00}'
(更新产品)DELETE http://127.0.0.1:8000/api/products/1/
(删除产品)GET http://127.0.0.1:8000/api/products/?in_stock=true&search=Test&ordering=-price
(过滤、搜索、排序)
这个简单的示例展示了DRF如何使用 ModelViewSet
和 Router
快速构建一个功能齐全的API。
5. 进一步学习方向
本文涵盖了DRF的核心组件。要更深入地掌握它,你可以探索以下主题:
- 自定义 Serializer 字段和验证: 处理更复杂的数据结构和业务逻辑。
- 关系型 Serializers: 处理模型间的关联关系(ForeignKey, ManyToManyField等)。
- 自定义 Views 和 ViewSets: 实现非标准的API逻辑。
- 自定义认证和权限类: 实现更细粒度的访问控制。
- 自定义 Renderer 和 Parser: 支持其他数据格式。
- API 文档: 使用
drf-yasg
或coreapi
等工具生成 Swagger/OpenAPI 文档。 - 测试 API: 使用DRF提供的
APIClient
进行单元和集成测试。 - 信号 (Signals): DRF提供了一些信号,可以在请求处理的不同阶段执行自定义逻辑。
- 性能优化: 序列化器优化、查询集优化等。
- 与其他库集成: OAuth, GraphQL 等。
DRF的官方文档非常详尽,是学习和查阅资料的最佳来源。
6. 总结
Django REST Framework 是构建Django API的基石。它提供了一套设计精良、功能强大的工具集,包括序列化器、视图、路由、认证、权限、分页、过滤、搜索等,极大地简化了API的开发过程。
通过理解并灵活运用DRF的核心概念,你可以快速高效地构建出符合RESTful原则、易于维护、性能优越的Web API,为你的Web应用提供强大的数据接口。
从简单的 ModelSerializer
和 ModelViewSet
入手,逐步学习和掌握DRF的各项功能,你将能够应对各种复杂的API开发需求。DRF不仅仅是一个框架,更是一种利用Django的强大能力构建现代API的强大范式。
希望本文能为你理解和入门DRF提供坚实的基础。祝你在使用DRF的道路上越走越远!