一、DRF概述
Django REST Framework(简称DRF)是构建RESTful API的强大工具包,建立在Django之上,提供了序列化、认证、权限、视图集、路由等完整的API开发组件。DRF遵循Django的设计哲学——"约定优于配置",同时提供了极高的灵活性,让开发者能够快速构建出高质量的Web API。
1.1 安装与配置
使用pip安装DRF非常简单,同时建议安装配套的过滤支持和文档生成工具:
pip install djangorestframework
pip install django-filter
pip install drf-spectacular # Swagger文档生成
在Django项目的settings.py中,将rest_framework注册到INSTALLED_APPS列表中:
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
# ...
'rest_framework',
'drf_spectacular', # API文档
]
推荐在settings.py中配置全局的DRF设置,包括默认的认证方式、权限策略、分页大小等:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
'rest_framework_simplejwt.authentication.JWTAuthentication',
],
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
'DEFAULT_PAGINATION_CLASS':
'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10,
'DEFAULT_SCHEMA_CLASS': 'drf_spectacular.openapi.AutoSchema',
}
1.2 序列化与反序列化
序列化是DRF的核心概念,指将Python对象(如Django模型实例、Queryset)转换为JSON、XML等前端可消费的格式;反序列化则是将前端提交的JSON数据解析为Python对象,并经过校验后存入数据库。DRF的Serializer类同时承担了序列化和反序列化的职责,通过同一个类完成数据的双向转换。
1.3 请求响应处理
DRF对Django原生的HttpRequest进行了封装,提供了Request对象,它自动解析JSON请求体;同时提供了Response对象,替代Django的HttpResponse,自动将数据渲染为合适的格式(JSON默认)。此外,DRF还提供了状态码常量(status.HTTP_200_OK、status.HTTP_400_BAD_REQUEST等),让API响应更加语义化。
二、序列化器(Serializers)
序列化器是DRF的基石,负责数据的序列化与反序列化。DRF提供了多种序列化器,适应不同场景的需求。
2.1 Serializer基本序列化
最基本的Serializer类需要手动定义每个字段,适合完全自定义的数据结构。例如,定义一个简单的博客文章序列化器:
from rest_framework import serializers
class ArticleSerializer(serializers.Serializer):
id = serializers.IntegerField(read_only=True)
title = serializers.CharField(max_length=200)
content = serializers.CharField()
author = serializers.CharField(max_length=100)
created_at = serializers.DateTimeField(read_only=True)
def create(self, validated_data):
return Article.objects.create(**validated_data)
def update(self, instance, validated_data):
instance.title = validated_data.get('title', instance.title)
instance.content = validated_data.get('content', instance.content)
instance.save()
return instance
可以看到,基本Serializer需要手动实现create()和update()方法,适合非模型数据或复杂自定义逻辑。
2.2 ModelSerializer自动生成
ModelSerializer是日常开发中使用频率最高的序列化器,它能根据Django模型自动推断字段定义、验证规则以及create/update方法,大幅减少重复代码:
class ArticleSerializer(serializers.ModelSerializer):
class Meta:
model = Article
fields = ['id', 'title', 'content', 'author', 'created_at']
read_only_fields = ['id', 'created_at']
通过fields指定需要暴露的字段,使用'__all__'表示全部字段,使用exclude排除不需要的字段。read_only_fields指定只读字段(通常是服务器自动生成的字段如id、created_at)。
2.3 字段定义与验证
ModelSerializer支持字段级别的验证和方法级别的验证。字段验证可以通过在Meta中覆盖字段定义来实现,也可以使用validate_方法进行自定义逻辑校验:
class ArticleSerializer(serializers.ModelSerializer):
# 覆盖自动生成的字段,添加额外约束
title = serializers.CharField(min_length=5, max_length=200)
class Meta:
model = Article
fields = '__all__'
# 字段级验证
def validate_title(self, value):
if '敏感词' in value:
raise serializers.ValidationError("标题包含非法内容")
return value
# 对象级验证
def validate(self, data):
if data['end_date'] and data['start_date'] and \
data['end_date'] <= data['start_date']:
raise serializers.ValidationError("结束日期必须晚于开始日期")
return data
2.4 嵌套序列化
当模型之间存在外键或多对多关系时,嵌套序列化用于展现关联对象的信息。DRF支持只读嵌套(直接嵌套另一个序列化器)和可写嵌套(需要自定义create/update方法):
class CommentSerializer(serializers.ModelSerializer):
class Meta:
model = Comment
fields = ['id', 'content', 'created_at']
class ArticleSerializer(serializers.ModelSerializer):
comments = CommentSerializer(many=True, read_only=True)
author_detail = serializers.SerializerMethodField()
class Meta:
model = Article
fields = ['id', 'title', 'comments', 'author_detail']
def get_author_detail(self, obj):
return {
'username': obj.author.username,
'email': obj.author.email,
}
SerializerMethodField允许动态计算返回数据,适合无需单独定义序列化器的简单转换。
2.5 反序列化与数据校验
反序列化流程中,is_valid()触发所有验证规则,验证通过后validated_data包含清洗后的数据,errors字典包含校验失败信息。开发者可以在视图中如下使用:
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
article = serializer.save() # 调用create()或update()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
三、视图(Views)
DRF提供了从函数视图到完整视图集的多种抽象层次,开发者可以根据需求的复杂度选择合适的视图类型。
3.1 @api_view装饰器(函数视图)
@api_view是DRF中最低层级的视图方式,基于Django的普通函数视图,添加了DRF的请求处理、响应渲染和异常处理能力。适合非常简单的API端点:
from rest_framework.decorators import api_view
from rest_framework.response import Response
@api_view(['GET', 'POST'])
def article_list(request):
if request.method == 'GET':
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = ArticleSerializer(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)
3.2 APIView类视图
APIView是DRF中所有类视图的基类,继承了Django的View类,并添加了认证、权限、限流等支持。通过类方法区分HTTP方法,代码更加模块化:
class ArticleList(APIView):
def get(self, request, format=None):
articles = Article.objects.all()
serializer = ArticleSerializer(articles, many=True)
return Response(serializer.data)
def post(self, request, format=None):
serializer = ArticleSerializer(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)
3.3 GenericAPIView通用视图
GenericAPIView在APIView的基础上增加了queryset、serializer_class、lookup_field等属性,并与Mixin类搭配使用,大幅简化常见CRUD操作的代码量:
class ArticleList(GenericAPIView,
ListModelMixin, CreateModelMixin):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
def get(self, request, *args, **kwargs):
return self.list(request, *args, **kwargs)
def post(self, request, *args, **kwargs):
return self.create(request, *args, **kwargs)
3.4 Mixin混合类
DRF内置了五个Mixin类,分别对应五种基础操作,开发者可以根据需要组合使用:
- ListModelMixin — 列表查询,对应GET请求,返回queryset列表
- CreateModelMixin — 创建资源,对应POST请求,创建新对象
- RetrieveModelMixin — 单个查询,对应GET请求(带pk),返回单个对象
- UpdateModelMixin — 更新资源,对应PUT/PATCH请求,更新现有对象
- DestroyModelMixin — 删除资源,对应DELETE请求,删除对象
Mixin类提供的是行为(action),将它们与GenericAPIView组合,即可快速构建完整的CRUD视图。
3.5 ViewSet视图集
ViewSet将一组相关的操作聚合到一个类中,通过Router自动映射URL。ViewSet继承自ViewSetMixin和APIView,将HTTP方法与自定义action关联:
class ArticleViewSet(ViewSet):
def list(self, request):
queryset = Article.objects.all()
serializer = ArticleSerializer(queryset, many=True)
return Response(serializer.data)
def create(self, request):
serializer = ArticleSerializer(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)
def retrieve(self, request, pk=None):
article = get_object_or_404(Article, pk=pk)
serializer = ArticleSerializer(article)
return Response(serializer.data)
def update(self, request, pk=None):
article = get_object_or_404(Article, pk=pk)
serializer = ArticleSerializer(article, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors,
status=status.HTTP_400_BAD_REQUEST)
def destroy(self, request, pk=None):
article = get_object_or_404(Article, pk=pk)
article.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
3.6 ModelViewSet完整CRUD
ModelViewSet继承自GenericAPIView,并组合了ListModelMixin、CreateModelMixin、RetrieveModelMixin、UpdateModelMixin、DestroyModelMixin五大Mixin。只需指定queryset和serializer_class,即可获得完整的CRUD端点,是日常开发中最高效的视图选择:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def perform_create(self, serializer):
# 自动填充当前用户为作者
serializer.save(author=self.request.user)
ModelViewSet还支持通过@action装饰器添加自定义端点,比如给文章点赞、发布草稿等业务操作:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@action(detail=True, methods=['post'])
def publish(self, request, pk=None):
article = self.get_object()
article.status = 'published'
article.save()
return Response({'status': 'published'})
四、路由器(Routers)
路由器是DRF将ViewSet与URL配置解耦的关键组件。它自动为ViewSet中的每个action生成对应的URL模式,省去了手动编写urlpatterns的繁琐工作。
4.1 DefaultRouter自动生成URL
DefaultRouter是功能最完整的路由器,它会为ViewSet的list和detail视图自动生成URL,同时还会生成一个API根视图(列出所有注册的端点)和一个可浏览的API页面:
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet, UserViewSet
router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')
router.register(r'users', UserViewSet, basename='user')
urlpatterns = [
path('', include(router.urls)),
]
上述配置自动生成以下URL模式:GET /articles/(列表)、POST /articles/(创建)、GET /articles/{id}/(详情)、PUT /articles/{id}/(全量更新)、PATCH /articles/{id}/(部分更新)、DELETE /articles/{id}/(删除)。
4.2 SimpleRouter
SimpleRouter与DefaultRouter的功能基本相同,区别在于SimpleRouter不会生成API根视图,也不会生成可浏览的API页面,适合仅需API功能的项目。SimpleRouter默认只生成标准的list和detail URL,但同样支持@action装饰器定义的自定义路由。
4.3 自定义路由
对于特殊需求,可以自定义路由类,继承BaseRouter并实现get_urls()方法。更常见的方式是使用@action装饰器为ViewSet添加自定义端点,路由器会自动识别并生成URL。@action支持detail=True(在单个资源上操作)和detail=False(在集合上操作),并通过url_path参数自定义URL路径名。
五、认证与权限
认证(Authentication)解决的是"你是谁"的问题,权限(Permission)解决的是"你能做什么"的问题。两者组合使用,构建安全的API访问控制体系。
5.1 认证方式
- BasicAuthentication — 基于HTTP Basic Auth,适合测试环境,生产环境不建议使用(明文传输凭据)。
- SessionAuthentication — 基于Django Session,适合与前端共享Session的Web应用,利用CSRF token防止跨站请求伪造。
- TokenAuthentication — DRF内置的Token认证,简单易用但缺乏过期机制,适合小型项目或内部API。
- JWTAuthentication — 通过djangorestframework-simplejwt实现,使用JSON Web Token,支持过期时间、刷新令牌,是目前最流行的API认证方式。
JWT认证配置示例:
from datetime import timedelta
SIMPLE_JWT = {
'ACCESS_TOKEN_LIFETIME': timedelta(minutes=30),
'REFRESH_TOKEN_LIFETIME': timedelta(days=1),
'AUTH_HEADER_TYPES': ('Bearer',),
'AUTH_TOKEN_CLASSES': (
'rest_framework_simplejwt.tokens.AccessToken',
),
}
5.2 内置权限类
- AllowAny — 允许所有访问(无论是否认证),适合公开API
- IsAuthenticated — 仅允许已认证用户访问
- IsAdminUser — 仅允许管理员(is_staff=True)访问
- IsAuthenticatedOrReadOnly — 未认证用户只能读取(GET/HEAD/OPTIONS),认证用户可以写入
权限可以在全局设置中配置,也可以在单个视图或ViewSet中覆盖:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
def get_permissions(self):
if self.action == 'destroy':
return [IsAdminUser()]
return super().get_permissions()
5.3 自定义权限
继承BasePermission类并重写has_permission(视图级别)和has_object_permission(对象级别)方法,可以实现细粒度的权限控制,比如只允许资源所有者编辑自己的文章:
from rest_framework.permissions import BasePermission
class IsOwner(BasePermission):
def has_object_permission(self, request, view, obj):
return obj.author == request.user
在ViewSet中配合使用:`permission_classes = [IsAuthenticated, IsOwner]`,确保只有登录用户中的资源所有者可以操作。
六、过滤、搜索与排序
DRF提供了强大的过滤、搜索和排序支持,让客户端可以灵活地查询所需数据。
6.1 django-filter集成
django-filter是Django生态中最流行的过滤库,DRF通过DjangoFilterBackend直接集成,支持精确匹配、范围查询、模糊搜索等多种过滤方式。首先定义FilterSet:
import django_filters
from .models import Article
class ArticleFilter(django_filters.FilterSet):
title = django_filters.CharFilter(lookup_expr='icontains')
created_after = django_filters.DateFilter(
field_name='created_at', lookup_expr='gte')
created_before = django_filters.DateFilter(
field_name='created_at', lookup_expr='lte')
class Meta:
model = Article
fields = ['status', 'author']
然后在视图中配置filter_backends和filterset_class:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [DjangoFilterBackend]
filterset_class = ArticleFilter
客户端即可通过URL参数进行过滤:`/api/articles/?status=published&created_after=2025-01-01`。
6.2 SearchFilter搜索
SearchFilter实现基于文本的全文搜索,通过search查询参数传递关键字。search_fields指定哪些字段参与搜索,支持^(开头匹配)、=(精确匹配)、@(全文搜索)、$(正则匹配)前缀:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [SearchFilter]
search_fields = ['^title', 'content']
客户端请求:`/api/articles/?search=Django`,会返回所有标题以"Django"开头或内容包含"Django"的文章。
6.3 OrderingFilter排序
OrderingFilter允许客户端通过ordering参数对结果进行排序,ordering_fields限定可排序的字段集合:
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
filter_backends = [OrderingFilter]
ordering_fields = ['created_at', 'title']
ordering = ['-created_at'] # 默认排序
客户端请求:`/api/articles/?ordering=-created_at`即按创建时间倒序排列。
6.4 分页
DRF提供了三种内置分页器,可以根据项目需求选择:
- PageNumberPagination — 基于页码的分页,客户端指定page参数,适合绝大多数场景。可通过page_size_query_param允许客户端自定义每页数量。
- LimitOffsetPagination — 基于偏移量的分页,客户端指定limit(数量)和offset(起始位置),适合需要精确位置控制的场景。
- CursorPagination — 基于游标的分页,客户端通过cursor参数翻页,性能最优且数据一致性最好,但只能向前或向后翻页(不能跳转到指定页)。
自定义分页器示例:
class CustomPagination(PageNumberPagination):
page_size = 20
page_size_query_param = 'page_size'
max_page_size = 100
七、限流(Throttling)
限流机制用于控制客户端在单位时间内可以发起的请求数量,防止API被滥用。DRF内置了多种限流类,同时也支持自定义限流策略。
7.1 AnonRateThrottle
AnonRateThrottle针对未认证的匿名用户进行限流。DRF通过请求的IP地址区分不同的匿名用户。适合限制公开API的调用频率,防止爬虫过度访问:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/hour', # 匿名用户每小时最多100次请求
}
}
7.2 UserRateThrottle
UserRateThrottle针对已认证的用户进行限流。DRF通过user进行区分,因此即使用户切换IP地址,限流依然有效。适合需要区分付费用户和免费用户使用频率的场景:
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.UserRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'user': '1000/day', # 登录用户每天最多1000次请求
}
}
7.3 ScopedRateThrottle
ScopedRateThrottle允许针对特定的视图或API端点设置不同的限流速率,通过在视图类中定义throttle_scope属性实现更精细的控制。比如对计算密集型接口设置更严格的限制:
class ExportView(APIView):
throttle_scope = 'exports'
throttle_classes = [ScopedRateThrottle]
def get(self, request):
# 导出大量数据的复杂操作
...
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'exports': '10/hour', # 导出接口每小时最多10次
}
}
7.4 自定义限流
继承SimpleRateThrottle并重写get_cache_key方法,可以实现自定义限流策略。例如,按API Key进行限流,或对特定用户组设置不同速率。自定义限流类可以灵活控制限流粒度和适用范围,满足复杂业务需求。
八、API文档
自动生成API文档是DRF生态的重要优势。当前最推荐的方式是使用drf-spectacular,它基于OpenAPI 3.0标准,生成规范且美观的Swagger文档。
8.1 drf-spectacular配置
首先安装并注册drf-spectacular,然后在项目的urls.py中配置文档视图:
from drf_spectacular.views import (
SpectacularAPIView,
SpectacularSwaggerView,
SpectacularRedocView,
)
urlpatterns = [
# OpenAPI Schema 文件
path('api/schema/',
SpectacularAPIView.as_view(), name='schema'),
# Swagger UI(交互式文档)
path('api/docs/',
SpectacularSwaggerView.as_view(url_name='schema'),
name='swagger-ui'),
# ReDoc UI(替代风格文档)
path('api/redoc/',
SpectacularRedocView.as_view(url_name='schema'),
name='redoc'),
]
8.2 文档描述配置
通过装饰器或类属性为API端点添加详细的描述信息,使生成的文档更加丰富易用:
from drf_spectacular.utils import (
extend_schema, extend_schema_view,
OpenApiParameter, OpenApiExample,
)
@extend_schema(
summary='获取文章列表',
description='返回分页的文章列表,支持过滤和搜索',
parameters=[
OpenApiParameter(
name='search',
description='搜索关键词',
required=False,
type=str),
OpenApiParameter(
name='status',
description='文章状态:draft/published',
required=False,
type=str),
],
responses={200: ArticleSerializer(many=True)},
)
def list(self, request, *args, **kwargs):
return super().list(request, *args, **kwargs)
8.3 API交互测试
Swagger UI提供了强大的交互式测试功能,开发者可以直接在浏览器中填写参数并发送请求,无需额外使用Postman等工具。文档页面上展示了每个端点的请求方法、URL路径、请求参数、请求体格式以及响应示例,方便前端开发者快速对接。ReDoc则提供了更适合阅读的文档呈现方式,两者结合可以覆盖开发者和消费者的不同需求。
最佳实践:在settings.py中通过SPECTACULAR_SETTINGS配置文档标题、版本、描述等元信息。将API文档部署在独立的环境中,开发环境和测试环境开放文档访问,生产环境可以关闭文档以避免安全风险。