Django REST Framework (DRF) 介绍:从入门到精通
在现代Web开发中,API (Application Programming Interface) 扮演着至关重要的角色,它是不同应用之间数据交互的桥梁。Django,作为Python领域最流行的Web框架之一,以其“开箱即用”和强大的功能赢得了广大开发者的喜爱。然而,Django本身主要用于构建传统的Web应用(HTML页面渲染),在构建RESTful API方面,它的原生支持相对有限。
这时候,Django REST Framework (DRF) 应运而生。DRF 是一个强大而灵活的工具包,用于在 Django 的基础上快速构建高质量的 RESTful API。它提供了一系列开箱即用的功能,极大地简化了API的开发过程,让开发者能够专注于业务逻辑而非底层实现。
1. 什么是 RESTful API?为什么选择 DRF?
1.1 RESTful API 简介
REST (Representational State Transfer) 是一种架构风格,它定义了一组约束和原则,用于创建可扩展、易于理解和维护的分布式系统。符合 REST 约束的 API 被称为 RESTful API。
RESTful API 的核心原则包括:
* 无状态 (Stateless):服务器不保存客户端的任何会话信息。
* 客户端-服务器 (Client-Server):客户端和服务器是分离的。
* 统一接口 (Uniform Interface):资源通过统一的接口进行操作,通常使用标准的 HTTP 方法(GET, POST, PUT, DELETE)。
* 可缓存 (Cacheable):客户端可以缓存响应以提高性能。
* 分层系统 (Layered System):系统可以由多层服务器组成。
1.2 为什么选择 DRF?
DRF 建立在 Django 的坚实基础上,并提供了构建 RESTful API 所需的几乎所有工具。它的优势在于:
* 易于使用和学习:良好的文档和与 Django 相似的开发模式,降低了学习曲线。
* 高度可定制:DRF 的组件设计灵活,允许开发者根据需求进行扩展和定制。
* 强大的序列化器 (Serializers):轻松将 Django ORM 模型转换为 JSON/XML 等格式,反之亦然,并处理数据验证。
* 丰富的视图类 (View Classes):提供通用视图和视图集,减少重复代码。
* 灵活的认证和权限系统:支持多种认证方式(Token, Session, OAuth2 等)和细粒度的权限控制。
* 内置浏览器可浏览 API:提供一个美观且功能齐全的Web界面,方便测试和调试 API。
* 多功能工具集:包括认证、权限、节流、过滤、分页、版本控制等功能。
2. 入门:安装与基本配置
2.1 安装
首先,确保你已经安装了 Django。然后,通过 pip 安装 DRF:
bash
pip install djangorestframework
2.2 配置
在你的 Django 项目的 settings.py 文件中,将 rest_framework 添加到 INSTALLED_APPS 中:
“`python
myproject/settings.py
INSTALLED_APPS = [
# …
‘rest_framework’,
]
“`
为了让 DRF 拥有一个默认的配置,你可以在 settings.py 中添加 REST_FRAMEWORK 字典。例如,设置默认的渲染器和解析器:
“`python
myproject/settings.py
REST_FRAMEWORK = {
‘DEFAULT_RENDERER_CLASSES’: [
‘rest_framework.renderers.JSONRenderer’,
‘rest_framework.renderers.BrowsableAPIRenderer’, # 允许在浏览器中直接访问 API
],
‘DEFAULT_PARSER_CLASSES’: [
‘rest_framework.parsers.JSONParser’,
‘rest_framework.parsers.FormParser’,
‘rest_framework.parsers.MultiPartParser’
]
}
“`
2.3 简单示例:创建第一个 API
我们以一个简单的 Book 模型为例:
1. 定义模型 (myapp/models.py)
“`python
myapp/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
publication_date = models.DateField()
isbn = models.CharField(max_length=13, unique=True)
def __str__(self):
return self.title
别忘了运行 `makemigrations` 和 `migrate`:bash
python manage.py makemigrations myapp
python manage.py migrate
“`
2. 创建序列化器 (myapp/serializers.py)
序列化器负责将 Django 模型实例转换为 Python 原生数据类型,然后可以很方便地渲染成 JSON 或 XML。它也处理反序列化(将原生数据类型转换回模型实例)以及数据验证。
“`python
myapp/serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = [‘id’, ‘title’, ‘author’, ‘publication_date’, ‘isbn’]
``ModelSerializer` 是一种快捷方式,它会自动根据模型字段生成序列化器字段。
3. 创建视图 (myapp/views.py)
视图处理 HTTP 请求,并返回 HTTP 响应。DRF 提供了多种视图类型,从最基础的 APIView 到功能强大的 ModelViewSet。
“`python
myapp/views.py
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer
class BookListCreateAPIView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
``ListCreateAPIView提供了处理 GET (列表) 和 POST (创建) 请求的功能。RetrieveUpdateDestroyAPIView` 提供了处理 GET (详情)、PUT (更新) 和 DELETE (删除) 请求的功能。
4. 配置 URL (myapp/urls.py 和 myproject/urls.py)
首先在 myapp 下创建 urls.py:
“`python
myapp/urls.py
from django.urls import path
from .views import BookListCreateAPIView, BookRetrieveUpdateDestroyAPIView
urlpatterns = [
path(‘books/’, BookListCreateAPIView.as_view(), name=’book-list-create’),
path(‘books/
]
然后将其包含到项目的 `urls.py` 中:python
myproject/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘myapp.urls’)), # 将 DRF API 路由包含在 ‘/api/’ 下
]
“`
现在运行 Django 开发服务器 python manage.py runserver,并访问 http://127.0.0.1:8000/api/books/,你就能看到 DRF 提供的浏览器可浏览 API 界面。
3. DRF 核心组件详解
3.1 Serializers (序列化器)
序列化器是 DRF 的核心。它们将复杂数据类型(如 Django 模型实例)序列化为 Python 原生数据类型,以便轻松地将其渲染为 JSON 或 XML 等内容类型。序列化器还可以反序列化以验证传入数据,并将其转换回模型实例。
常用序列化器类型:
* serializers.Serializer:最基础的序列化器,用于定义任意数据结构。
* serializers.ModelSerializer:与 Django Model 类绑定的序列化器,自动生成字段,并提供 create() 和 update() 方法。
* serializers.ListSerializer:用于处理一组对象的序列化和反序列化。
字段选项:
序列化器字段支持许多选项,如 read_only=True (只读), write_only=True (只写), required=False (可选), source='model_field_name' (映射到不同模型字段名), default=some_value, validators=[some_validator] 等。
数据验证:
* 字段级别验证:在序列化器字段上直接定义验证规则。
* 对象级别验证:通过在序列化器中定义 validate 方法进行。
* 自定义验证器:创建独立的验证函数或类。
“`python
myapp/serializers.py (示例:自定义验证)
class BookSerializer(serializers.ModelSerializer):
# 自定义字段,如出版年份只读
publication_year = serializers.SerializerMethodField()
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date', 'isbn', 'publication_year']
# 为 ISBN 字段添加自定义验证器
extra_kwargs = {'isbn': {'validators': [self.validate_isbn]}}
def get_publication_year(self, obj):
return obj.publication_date.year
def validate_title(self, value):
"""
验证书名是否包含敏感词
"""
if "敏感词" in value.lower():
raise serializers.ValidationError("书名不能包含敏感词。")
return value
def validate(self, data):
"""
对象级别验证:确保出版日期不晚于今天
"""
if data['publication_date'] > datetime.date.today():
raise serializers.ValidationError({"publication_date": "出版日期不能在未来。"})
return data
def validate_isbn(self, value):
"""
自定义 ISBN 验证函数 (作为 extra_kwargs 的一部分)
"""
if not value.isdigit() or len(value) != 13:
raise serializers.ValidationError("ISBN 必须是13位数字。")
return value
“`
3.2 Views (视图)
DRF 提供了多种视图类型,以适应不同的需求和开发风格。
1. APIView (最基础)
APIView 是 Django 的 View 类的 DRF 版本。它提供了处理传入请求的 request 对象、自定义渲染器、解析器、认证、权限、节流等功能。你需要为每个 HTTP 方法(get, post, put, delete 等)定义相应的方法。
“`python
myapp/views.py (APIView 示例)
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
class BookListAPI(APIView):
def get(self, request, format=None):
books = Book.objects.all()
serializer = BookSerializer(books, many=True)
return Response(serializer.data)
def post(self, request, format=None):
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)
“`
优点:完全控制请求-响应流程。
缺点:需要编写更多代码。
2. Generic Views (通用视图)
通用视图是 APIView 的扩展,它们提供了常用的操作(如列表、创建、检索、更新、删除)的混合类 (Mixins)。结合 generics.GenericAPIView,你可以快速构建 RESTful 视图。
ListModelMixin: 处理列表查询。CreateModelMixin: 处理创建。RetrieveModelMixin: 处理详情查询。UpdateModelMixin: 处理更新。DestroyModelMixin: 处理删除。
“`python
myapp/views.py (Generic Views 示例)
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer
class BookListCreateAPIView(generics.ListCreateAPIView):
# 结合 ListModelMixin 和 CreateModelMixin
queryset = Book.objects.all()
serializer_class = BookSerializer
class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
# 结合 RetrieveModelMixin, UpdateModelMixin 和 DestroyModelMixin
queryset = Book.objects.all()
serializer_class = BookSerializer
“`
这是最常用的视图类型,兼顾灵活性和开发效率。
3. ViewSets (视图集)
视图集将多个相关的视图逻辑(如列表、创建、检索、更新、删除)组合到一个类中,而不是为每个操作创建单独的视图。这对于资源上的 CRUD 操作非常有用。
ViewSet:最基础的视图集。GenericViewSet:提供了GenericAPIView的功能,但没有预设操作。ModelViewSet:继承自GenericViewSet和所有通用视图混入类,提供了完整的 CRUD 功能。
“`python
myapp/views.py (ViewSet 示例)
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
“`
优点:极大地减少了代码量,特别适合标准 CRUD 操作。
缺点:在某些情况下可能过于“魔幻”,隐藏了部分逻辑。
3.3 Routers (路由)
当使用 ViewSet 时,通常会配合 Router 来自动生成 URL 配置。这比手动定义每个 URL 路径更方便。
“`python
myproject/urls.py (使用 Router)
from django.contrib import admin
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from myapp.views import BookViewSet
router = DefaultRouter()
router.register(r’books’, BookViewSet) # 注册 BookViewSet,它将自动生成列表、详情等 URL
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(router.urls)), # 将 router 的 URL 包含进来
]
``DefaultRouter会自动为BookViewSet生成如/api/books/(GET, POST) 和/api/books/{pk}/` (GET, PUT, PATCH, DELETE) 等 URL。
3.4 Requests & Responses
- Request 对象:DRF 扩展了 Django 的
HttpRequest对象,提供了request.data(解析后的请求体,支持多种内容类型),request.query_params(GET 请求参数),request.user(认证用户) 等属性。 - Response 对象:DRF 的
Response对象继承自Django的HttpResponse,但它会根据请求的Accept头部自动选择最合适的渲染器来渲染数据。你可以直接传递 Python 原生数据类型给Response。
4. 认证与权限 (Authentication & Permissions)
API 的安全至关重要。DRF 提供了灵活的认证 (Authentication) 和权限 (Permission) 机制。
4.1 认证 (Authentication)
认证是识别请求发起者身份的过程。DRF 支持多种认证方式:
* SessionAuthentication:基于 Django 的会话认证,适合与浏览器会话一起使用。
* BasicAuthentication:基于 HTTP Basic Authentication,每次请求都发送用户名密码。
* TokenAuthentication:基于令牌的认证,客户端在每次请求时发送一个令牌。这是 RESTful API 最常用的方式之一。
* OAuth2Authentication:支持 OAuth2 协议。
配置认证类:
可以在 settings.py 中全局配置:
python
REST_FRAMEWORK = {
# ...
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication', # 优先使用 Token 认证
'rest_framework.authentication.SessionAuthentication',
],
# ...
}
也可以在视图中局部配置:
“`python
from rest_framework.authentication import TokenAuthentication
from rest_framework.permissions import IsAuthenticated
class BookListCreateAPIView(generics.ListCreateAPIView):
authentication_classes = [TokenAuthentication]
permission_classes = [IsAuthenticated]
queryset = Book.objects.all()
serializer_class = BookSerializer
“`
4.2 权限 (Permissions)
权限是在用户身份认证成功后,决定其是否可以执行某个操作。
DRF 提供了多种内置权限类:
* AllowAny:允许所有用户访问 (默认)。
* IsAuthenticated:只允许认证用户访问。
* IsAdminUser:只允许管理员用户访问。
* IsAuthenticatedOrReadOnly:允许认证用户完全访问,未认证用户只读。
* DjangoModelPermissions:基于 Django 的模型权限。
* DjangoObjectPermissions:基于 Django 的对象级别权限 (需要 django-guardian 等库)。
自定义权限:
通过继承 rest_framework.permissions.BasePermission 类并重写 has_permission 或 has_object_permission 方法来自定义权限逻辑。
“`python
myapp/permissions.py
from rest_framework import permissions
class IsAuthorOrReadOnly(permissions.BasePermission):
“””
自定义权限,只允许作者编辑,其他人只读。
“””
def has_object_permission(self, request, view, obj):
# 允许 GET, HEAD, OPTIONS 请求
if request.method in permissions.SAFE_METHODS:
return True
# 写入权限只允许作者
return obj.author == request.user.username # 假设 author 字段存储用户名
在视图中使用:python
myapp/views.py
from .permissions import IsAuthorOrReadOnly
class BookRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [IsAuthorOrReadOnly]
“`
5. 分页、过滤与搜索 (Pagination, Filtering & Searching)
对于大型数据集,DRF 提供了强大的功能来管理数据的呈现。
5.1 分页 (Pagination)
DRF 提供了多种分页器:
* PageNumberPagination:基于页码的分页。
* LimitOffsetPagination:基于偏移量和限制的分页。
* CursorPagination:基于游标的分页,适用于无限滚动,性能更好。
配置分页:
全局配置 (在 settings.py):
python
REST_FRAMEWORK = {
# ...
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10, # 每页10条记录
}
局部配置 (在视图中):
“`python
from rest_framework.pagination import PageNumberPagination
class CustomPageNumberPagination(PageNumberPagination):
page_size = 5
page_size_query_param = ‘page_size’ # 允许客户端通过 page_size 参数控制每页大小
max_page_size = 100
class BookListCreateAPIView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = CustomPageNumberPagination
“`
5.2 过滤 (Filtering)
DRF 内置了 DjangoFilterBackend,允许你通过 URL 查询参数过滤数据。需要安装 django-filter:
bash
pip install django-filter
在 settings.py 中添加:
python
INSTALLED_APPS = [
# ...
'django_filters',
]
REST_FRAMEWORK = {
# ...
'DEFAULT_FILTER_BACKENDS': [
'django_filters.rest_framework.DjangoFilterBackend'
],
}
然后在视图中指定过滤字段:
“`python
from rest_framework import filters
from django_filters.rest_framework import DjangoFilterBackend
class BookListCreateAPIView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = [‘author’, ‘publication_date’] # 允许通过 ?author=xxx&publication_date=yyyy-mm-dd 过滤
``django-filter
更复杂的过滤可以使用的FilterSet` 类。
5.3 搜索 (Searching)
DRF 提供了 SearchFilter,允许你通过一个搜索参数在指定字段中进行文本搜索。
“`python
from rest_framework import filters
class BookListCreateAPIView(generics.ListCreateAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filter_backends = [filters.SearchFilter]
search_fields = [‘title’, ‘author’, ‘isbn’] # 允许通过 ?search=关键词 在这些字段中搜索
“`
6. 高级主题
6.1 自定义 Serializers 和 Fields
当 ModelSerializer 无法满足需求时,可以自定义 Serializer 或 SerializerMethodField。
* 嵌套序列化:当模型之间存在关系时,可以在序列化器中嵌套其他序列化器来表示相关数据。
* Writable Nested Serializers:处理嵌套数据的创建和更新。
“`python
假设有一个 Category 模型
class Category(models.Model):
name = models.CharField(max_length=50)
class Book(models.Model):
# …
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
myapp/serializers.py
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = [‘id’, ‘name’]
class BookSerializer(serializers.ModelSerializer):
category = CategorySerializer(read_only=True) # 嵌套序列化器,只读
category_id = serializers.PrimaryKeyRelatedField(
queryset=Category.objects.all(), source=’category’, write_only=True
) # 用于写入,接收 Category ID
class Meta:
model = Book
fields = ['id', 'title', 'author', 'publication_date', 'isbn', 'category', 'category_id']
extra_kwargs = {
'category': {'read_only': True} # 确保 category 字段在写入时只读
}
“`
6.2 自定义 ViewSets 和 Routers
除了 ModelViewSet,你还可以继承 GenericViewSet 并混入你需要的 Mixin 来构建自定义的 ViewSet,以获得更精细的控制。甚至可以自定义 Router 来生成更复杂的 URL 模式。
6.3 API Throttling (节流)
节流用于控制客户端可以发出的请求速率,防止滥用。
* AnonRateThrottle:针对匿名用户。
* UserRateThrottle:针对认证用户。
* ScopedRateThrottle:为不同作用域设置不同速率。
在 settings.py 中配置:
python
REST_FRAMEWORK = {
# ...
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '100/day', # 匿名用户每天100次请求
'user': '1000/day', # 认证用户每天1000次请求
}
}
也可以在视图中局部配置 throttle_classes。
6.4 Versioning (版本控制)
API 版本控制是管理 API 变更的重要策略,确保旧客户端的兼容性。DRF 支持多种版本控制方案:
* URLPathVersioning:通过 URL 路径 (/v1/books/)。
* NamespaceVersioning:通过 URL 命名空间 (url(r'^', include('app.urls', namespace='v1')))。
* QueryParameterVersioning:通过查询参数 (/books/?version=1.0)。
* HeaderVersioning:通过 HTTP 头 (Accept: application/json; version=1.0)。
全局配置:
python
REST_FRAMEWORK = {
# ...
'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
'DEFAULT_VERSION': 'v1',
'ALLOWED_VERSIONS': ['v1', 'v2'],
'VERSION_PARAM': 'version',
}
6.5 测试 DRF APIs
DRF 提供了 APIClient 和 APITestCase 来简化 API 测试。它们模拟 HTTP 请求,并提供方便的方法来检查响应。
“`python
myapp/tests.py
from django.urls import reverse
from rest_framework import status
from rest_framework.test import APITestCase
from .models import Book
class BookAPITestCase(APITestCase):
def setUp(self):
self.book_data = {‘title’: ‘Test Book’, ‘author’: ‘Test Author’, ‘publication_date’: ‘2023-01-01’, ‘isbn’: ‘1234567890123’}
self.book = Book.objects.create(**self.book_data)
self.list_url = reverse(‘book-list-create’) # 使用 URL 命名
self.detail_url = reverse(‘book-detail’, kwargs={‘pk’: self.book.pk})
def test_create_book(self):
response = self.client.post(self.list_url, self.book_data, format='json')
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(Book.objects.count(), 2)
def test_get_book_list(self):
response = self.client.get(self.list_url, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.assertEqual(len(response.data), 1)
def test_update_book(self):
updated_data = {'title': 'Updated Title', 'author': 'Updated Author', 'publication_date': '2023-02-01', 'isbn': '1234567890124'}
response = self.client.put(self.detail_url, updated_data, format='json')
self.assertEqual(response.status_code, status.HTTP_200_OK)
self.book.refresh_from_db()
self.assertEqual(self.book.title, 'Updated Title')
def test_delete_book(self):
response = self.client.delete(self.detail_url)
self.assertEqual(response.status_code, status.HTTP_204_NO_CONTENT)
self.assertEqual(Book.objects.count(), 0)
``python manage.py test myapp`
运行测试:
7. 最佳实践与提示
- API 文档:使用
drf-yasg或drf-spectacular等库自动生成 OpenAPI/Swagger 文档,极大地提高 API 的可用性。 - 异常处理:DRF 提供了统一的异常处理机制。你可以通过
EXCEPTION_HANDLER设置自定义异常处理函数。 - 性能优化:
- 使用
select_related和prefetch_related减少数据库查询。 - 优化序列化器中的字段,避免不必要的数据传输。
- 合理使用缓存。
- 使用
- 部署:在生产环境中,禁用
BrowsableAPIRenderer,并确保使用安全的认证方式(如 Token 认证)。
8. 总结
Django REST Framework 是构建强大、灵活和可维护的 RESTful API 的绝佳选择。从简单的序列化器和通用视图,到复杂的认证、权限、过滤、分页和版本控制,DRF 提供了全面的解决方案。通过深入理解其核心组件和最佳实践,你将能够高效地开发出高质量的 API,满足各种业务需求。
希望这篇详细的文章能帮助你从入门到精通 DRF!