从零开始,玩转数据接口:Django REST Framework (DRF) 入门指南
在现代软件开发中,构建健壮、高效且易于维护的 Web API(应用程序接口)变得越来越重要。无论是为移动应用提供后端服务,还是为前端单页应用(SPA)提供数据支持,或者仅仅是为了与其他系统进行数据交换,API 都扮演着核心角色。
对于 Django 开发者来说,构建 RESTful API 的首选框架便是 Django REST Framework (DRF)。它是一个强大而灵活的工具包,在 Django 的基础上提供了构建 Web API 所需的几乎所有功能,极大地简化了开发流程。
如果你已经熟悉 Django 的基础知识(如模型、视图、URLs、ORM等),但对如何构建 API 一无所知,那么这篇从零开始的指南就是为你准备的。我们将一步步深入了解 DRF 的核心概念,并通过实际例子来理解它们的作用。
文章目录:
- 为什么选择 Django REST Framework (DRF)?
- 准备工作:你需要了解什么?
- 环境搭建:安装与配置
- 核心概念一:序列化器 (Serializers)
- 序列化器的作用:数据转换与验证
- Serializer vs ModelSerializer
- 创建第一个 Serializer
- 序列化与反序列化实践
- 核心概念二:视图 (Views)
- APIView:API 版的 Django View
- Generic API Views:简化常见操作
- ViewSets:将相关逻辑打包
- 选择适合你的视图类型
- 核心概念三:URLs 与路由器 (Routers)
- 手动映射 APIView/Generic Views
- 使用 DefaultRouter 自动映射 ViewSets
- 请求与响应 (Requests & Responses)
- Request 对象:获取客户端数据
- Response 对象:构建返回数据
- 状态码的应用
- 权限与认证 (Authentication & Permissions)
- 为何需要认证和权限?
- 认证 (Authentication):你是谁?
- SessionAuthentication
- TokenAuthentication
- 权限 (Permissions):你能做什么?
- AllowAny, IsAuthenticated, IsAdminUser, IsAuthenticatedOrReadOnly
- 如何在视图中应用权限和认证
- 进阶特性 (简要介绍)
- 分页 (Pagination)
- 过滤与搜索 (Filtering & Searching)
- 限流 (Throttling)
- 测试 API
- API 文档
- 构建一个简单的 API 示例
- 总结与后续学习方向
1. 为什么选择 Django REST Framework (DRF)?
在深入学习之前,我们先来了解一下 DRF 的优势:
- 强大与灵活: DRF 提供了处理 API 开发中各种场景的工具,从序列化、请求处理到认证、权限、限流、分页等一应俱全。
- 基于 Django: 充分利用 Django 现有的优势,如 ORM、URL 路由系统、认证系统等,与 Django 项目无缝集成。
- 社区活跃: 拥有庞大的用户群和活跃的社区,遇到问题容易找到解决方案,文档详尽。
- 可视化 API 浏览器: 默认提供了强大的 API 浏览器界面,方便开发者测试和调试 API。
- 广泛的应用: 被许多公司用于构建生产级的 Web API。
简单来说,如果你正在使用 Django 并需要构建 API,DRF 是最自然、最高效的选择。
2. 准备工作:你需要了解什么?
正如文章开头所说,本指南假定你已经具备以下基础:
- Python 基础: 理解 Python 的语法、数据结构(列表、字典)、函数、类等。
- Django 基础:
- Django 项目结构
- 模型的定义与使用 (ORM)
- 基本的 Django 视图和 URL 路由
- 了解 settings.py 配置
- 虚拟环境 (Virtual Environment) 的使用
如果你对这些概念还不熟悉,强烈建议先花时间学习 Django 的官方教程或相关资源。
3. 环境搭建:安装与配置
首先,确保你已经在项目目录下激活了虚拟环境。如果还没有,请创建并激活一个:
“`bash
创建虚拟环境 (如果还没有)
python -m venv venv
激活虚拟环境 (Linux/macOS)
source venv/bin/activate
激活虚拟环境 (Windows)
venv\Scripts\activate
“`
接下来,安装 Django 和 Django REST Framework:
bash
pip install Django djangorestframework
安装完成后,你需要将 DRF 添加到 Django 项目的 settings.py
文件中的 INSTALLED_APPS
列表里:
“`python
your_project/settings.py
INSTALLED_APPS = [
# … other apps
‘django.contrib.admin’,
‘django.contrib.auth’,
‘django.contrib.contenttypes’,
‘django.contrib.sessions’,
‘django.contrib.messages’,
‘django.contrib.staticfiles’,
‘rest_framework’, # <– Add this line
# … your other apps
]
… rest of settings
“`
就是这样!DRF 现在已经集成到你的 Django 项目中了。
4. 核心概念一:序列化器 (Serializers)
序列化器是 DRF 中最核心的概念之一。它的主要作用是将复杂的数据类型(如 Django 模型对象或查询集)转换为易于传输的格式(如 JSON、XML 等),以及将接收到的数据(如 JSON)验证并转换回复杂的数据类型(如 Django 模型对象)。
你可以将序列化器类比为 Django 中的 Form 或 ModelForm。Form 用于处理 HTML 表单数据,而 Serializer 用于处理 API 数据。ModelForm 可以自动根据模型生成表单,ModelSerializer 也可以自动根据模型生成序列化器。
4.1 序列化器的作用:数据转换与验证
- 序列化 (Serialization): 将后端数据(如模型实例)转换为客户端需要的格式(通常是 Python 原生的数据类型,DRF 会将其进一步渲染成 JSON)。例如,将一个
Book
模型对象转换成一个 Python 字典:{'id': 1, 'title': '...', 'author': '...'}
,这个字典最终会变成 JSON 字符串。 - 反序列化 (Deserialization): 将客户端发送的数据(通常是 JSON,DRF 会将其解析成 Python 字典)验证后,转换成后端可以处理的数据类型(如用于创建或更新模型实例)。
4.2 Serializer vs ModelSerializer
Serializer
: 这是一个通用的序列化器类。你可以完全自定义其中的字段,不一定与任何模型绑定。适用于处理非模型数据或需要高度定制化输出/输入的场景。ModelSerializer
: 继承自Serializer
。它会自动根据指定的 Django 模型生成对应的序列化器字段。这是最常用的序列化器类型,可以大大减少编写重复代码。
4.3 创建第一个 Serializer (ModelSerializer)
假设你有一个 Django 应用 (my_app
),其中定义了一个简单的模型 Book
:
“`python
my_app/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
published_date = models.DateField()
isbn = models.CharField(max_length=13, unique=True)
def __str__(self):
return self.title
“`
为了能够通过 API 返回 Book
对象的数据,我们需要为其创建一个 ModelSerializer
。在 my_app
应用目录下创建一个 serializers.py
文件:
“`python
my_app/serializers.py
from rest_framework import serializers
from .models import Book
class BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
# fields = ‘all‘ # 包含模型所有字段
fields = [‘id’, ‘title’, ‘author’, ‘published_date’] # 指定包含的字段
# exclude = [‘isbn’] # 排除某些字段 (与 fields 互斥)
“`
在 ModelSerializer
中,我们通常在内部 Meta
类中指定 model
和 fields
(或 exclude
)。fields
指定了序列化器应该包含的模型字段。'__all__'
是一个快捷方式,表示包含模型中的所有字段。在这里,我们明确列出了希望在 API 输出中看到的字段。id
字段会自动被包含(除非你明确排除),因为它通常是资源的唯一标识符。
4.4 序列化与反序列化实践
在 Django Shell 中测试序列化器:
bash
python manage.py shell
“`python
In Django Shell
from my_app.models import Book
from my_app.serializers import BookSerializer
创建一些 Book 对象 (如果还没有)
book1 = Book.objects.create(title=’Django for Beginners’, author=’A. Developer’, published_date=’2023-01-01′, isbn=’111-1-11-111111-1′)
book2 = Book.objects.create(title=’DRF Master’, author=’B. Coder’, published_date=’2024-05-20′, isbn=’222-2-22-222222-2′)
— 序列化单个对象 —
1. 创建序列化器实例,传入要序列化的对象
serializer = BookSerializer(book1)
2. 访问 .data 属性获取序列化后的数据 (Python 字典)
print(serializer.data)
输出类似: {‘id’: 1, ‘title’: ‘Django for Beginners’, ‘author’: ‘A. Developer’, ‘published_date’: ‘2023-01-01’}
— 序列化多个对象 (查询集) —
1. 获取查询集
books = Book.objects.all()
2. 创建序列化器实例,传入查询集,并设置 many=True
serializer = BookSerializer(books, many=True)
3. 访问 .data 属性
print(serializer.data)
输出类似: [{‘id’: 1, …}, {‘id’: 2, …}]
— 反序列化 (验证和创建新对象) —
data = {‘title’: ‘New Book Title’, ‘author’: ‘New Author’, ‘published_date’: ‘2024-06-01’, ‘isbn’: ‘333-3-33-333333-3’}
1. 创建序列化器实例,传入要反序列化的数据
serializer = BookSerializer(data=data)
2. 调用 is_valid() 方法进行验证
print(serializer.is_valid()) # 返回 True 或 False
3. 如果验证通过,可以通过 .validated_data 访问验证后的数据 (Python 字典)
if serializer.is_valid():
print(serializer.validated_data)
# 4. 调用 .save() 方法创建或更新模型实例
# 对于新建,如果序列化器没有传入 instance,save() 会调用 serializer.create()
book_instance = serializer.save()
print(f”Created book: {book_instance.title}”)
else:
# 访问 .errors 属性查看验证错误信息
print(serializer.errors)
— 反序列化 (验证和更新现有对象) —
existing_book = Book.objects.get(id=1)
update_data = {‘title’: ‘Updated Title’} # 只更新 title
1. 创建序列化器实例,传入要更新的对象 (instance) 和更新数据 (data)
serializer = BookSerializer(instance=existing_book, data=update_data, partial=True) # partial=True 允许部分更新
2. 调用 is_valid() 方法进行验证
print(serializer.is_valid())
3. 如果验证通过,调用 .save() 方法
if serializer.is_valid():
# 如果序列化器传入了 instance,save() 会调用 serializer.update()
updated_book = serializer.save()
print(f”Updated book: {updated_book.title}”)
“`
is_valid()
方法是反序列化过程中必须调用的。它会检查传入的数据是否符合序列化器字段的定义(例如,字段类型、最大长度、是否必填等),并会触发模型字段的验证器。如果验证失败,serializer.errors
会包含详细的错误信息。serializer.save()
方法会根据是否传入 instance
来决定是创建新对象还是更新现有对象。
掌握序列化器是学习 DRF 的第一步,也是非常重要的一步。
5. 核心概念二:视图 (Views)
在 Django 中,视图函数/类接收 HttpRequest
对象并返回 HttpResponse
对象。DRF 中的视图也有类似的作用,但它们接收的是 DRF 的 Request
对象,并返回 DRF 的 Response
对象。DRF 的视图提供了更多的便利功能,特别是在处理 API 请求(如内容协商、解析请求体、格式化响应体)方面。
DRF 提供了多种视图类型,以适应不同的开发需求:
5.1 APIView:API 版的 Django View
rest_framework.views.APIView
是 DRF 视图的基础。它类似于 Django 的 View
类,你可以定义对应 HTTP 方法(get
, post
, put
, delete
等)的方法。
APIView 与 Django View 的主要区别在于:
- 接收 DRF 的
Request
对象,提供了更方便的数据访问(request.data
)。 - 返回 DRF 的
Response
对象,可以方便地返回各种格式的数据(默认为 JSON)。 - 提供了认证、权限、限流等机制的支持。
示例:
“`python
my_app/views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import Book
from .serializers import BookSerializer
class BookListAPIView(APIView):
“””
List all books, or create a new book.
“””
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)
class BookDetailAPIView(APIView):
“””
Retrieve, update or delete a book instance.
“””
def get_object(self, pk):
try:
return Book.objects.get(pk=pk)
except Book.DoesNotExist:
from django.http import Http404 # DRF exception handling converts this to 404
raise Http404
def get(self, request, pk, format=None):
book = self.get_object(pk)
serializer = BookSerializer(book)
return Response(serializer.data)
def put(self, request, pk, format=None):
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 delete(self, request, pk, format=None):
book = self.get_object(pk)
book.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
“`
这是一个典型的 RESTful API 实现,包含了获取列表/创建 (BookListAPIView
) 和获取详情/更新/删除 (BookDetailAPIView
) 的逻辑。
5.2 Generic API Views:简化常见操作
由于很多 API 视图都有相似的模式(例如,获取列表、获取详情、创建、更新、删除),DRF 提供了一组通用的视图类来减少重复代码。这些类通常与一个模型和序列化器绑定。
它们位于 rest_framework.generics
模块下:
ListAPIView
: 只读列表。CreateAPIView
: 只创建。RetrieveAPIView
: 只读详情。UpdateAPIView
: 只更新。DestroyAPIView
: 只删除。ListCreateAPIView
: 列表和创建。RetrieveUpdateAPIView
: 详情和更新。RetrieveDestroyAPIView
: 详情和删除。RetrieveUpdateDestroyAPIView
: 详情、更新和删除。
使用 Generic Views 编写上面的 Book API 示例会更简洁:
“`python
my_app/views.py (using Generic Views)
from rest_framework import generics
from .models import Book
from .serializers import BookSerializer
class BookListCreate(generics.ListCreateAPIView):
“””
List all books or create a new book.
“””
queryset = Book.objects.all() # 指定要查询的数据集
serializer_class = BookSerializer # 指定使用的序列化器
class BookRetrieveUpdateDestroy(generics.RetrieveUpdateDestroyAPIView):
“””
Retrieve, update or delete a book instance.
“””
queryset = Book.objects.all() # 指定要查询的数据集
serializer_class = BookSerializer # 指定使用的序列化器
# 查找单个对象的字段,默认为 ‘pk’
# lookup_field = ‘isbn’ # 如果想通过 isbn 查找,则设置此项
“`
Generic Views 通过设置 queryset
和 serializer_class
属性,或者覆盖相应的方法(如 get_queryset()
, get_serializer_class()
)来工作。它们极大地减少了 boilerplate 代码。
5.3 ViewSets:将相关逻辑打包
ViewSets 将一组相关的视图逻辑打包到一个类中,例如,一个 ModelViewSet
通常包含了对一个模型进行 CRUD (创建、读取、更新、删除) 的所有操作。
使用 ViewSets 的主要好处是:
- 代码组织更清晰,一个 ViewSet 对应一个资源的所有操作。
- 可以与 DRF 的 Routers 结合使用,自动生成 URL 配置,进一步简化代码。
ViewSets 位于 rest_framework.viewsets
模块下。最常用的是 ModelViewSet
,它继承自 GenericViewSet
并混合了 ListModelMixin
, RetrieveModelMixin
, CreateModelMixin
, UpdateModelMixin
, DestroyModelMixin
,从而提供了完整的 CRUD 功能。
使用 ViewSet 编写 Book API 示例:
“`python
my_app/views.py (using ViewSets)
from rest_framework import viewsets
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
“””
A ViewSet for viewing and editing Book instances.
“””
queryset = Book.objects.all()
serializer_class = BookSerializer
# lookup_field = ‘isbn’ # 如果想通过 isbn 查找,则设置此项
“`
这个 BookViewSet
类就包含了处理 /books/
(GET, POST) 和 /books/{pk}/
(GET, PUT, PATCH, DELETE) 请求的所有逻辑。
5.4 选择适合你的视图类型
- APIView: 当你需要完全控制请求和响应处理流程,或者处理非 CRUD 的复杂逻辑时使用。
- Generic API Views: 当你需要实现常见的 CRUD 操作,但又不想使用 ViewSets 带来的自动 URL 生成时使用,或者只需要实现部分 CRUD 操作(如只读)。
- ViewSets: 当你需要为一个资源提供完整的 CRUD 或大部分 CRUD 操作,并希望利用 Routers 自动生成 URL 配置时,这是最简洁高效的选择。对于大多数基于模型的 API,
ModelViewSet
是首选。
对于初学者来说,通常会从 APIView 开始理解基础概念,然后过渡到 Generic Views 学习如何简化代码,最后掌握 ViewSets 和 Routers 的强大组合。
6. 核心概念三:URLs 与路由器 (Routers)
定义 API 的 URL 路径是将客户端请求映射到相应的视图逻辑的必要步骤。
6.1 手动映射 APIView/Generic Views
如果你使用 APIView
或 Generic Views,你需要像处理普通 Django 视图一样,在应用的 urls.py
中手动定义 URL 模式:
“`python
my_app/urls.py (for APIView/Generic Views)
from django.urls import path
from .views import BookListAPIView, BookDetailAPIView # 如果使用 APIView
from .views import BookListCreate, BookRetrieveUpdateDestroy # 如果使用 Generic Views
urlpatterns = [
# path(‘books/’, BookListAPIView.as_view(), name=’book-list’), # APIView
# path(‘books/
path('books/', BookListCreate.as_view(), name='book-list-create'), # Generic Views
path('books/<int:pk>/', BookRetrieveUpdateDestroy.as_view(), name='book-detail-update-delete'), # Generic Views
]
“`
然后在项目的 urls.py
中包含这个应用的 URL 配置:
“`python
your_project/urls.py
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘my_app.urls’)), # 包含应用的 API URLs
]
“`
现在,你可以访问 /api/books/
和 /api/books/{pk}/
来与你的 API 交互了。
6.2 使用 DefaultRouter 自动映射 ViewSets
如果你使用了 ViewSets (特别是 ModelViewSet
),DRF 的 Routers 可以自动为你生成 URL 配置,这极大地简化了 URLs 定义。
rest_framework.routers.DefaultRouter
是最常用的路由器。它会自动为 ModelViewSet
注册 /basename/
(list/create) 和 /basename/{pk}/
(retrieve/update/delete) 两种模式的 URL。
修改 my_app/urls.py
以使用 Router:
“`python
my_app/urls.py (for ViewSets)
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSet
创建一个路由器实例
router = DefaultRouter()
注册 ViewSet 到路由器,第一个参数是 URL 前缀,第二个是 ViewSet 类
router.register(r’books’, BookViewSet, basename=’book’)
ViewSets 生成的 URL 会通过 router.urls 属性暴露
urlpatterns = [
path(”, include(router.urls)), # 包含路由器生成的 URLs
]
项目的 urls.py 保持不变,仍然是 path(‘api/’, include(‘my_app.urls’)),
“`
router.register()
的第一个参数 r'books'
定义了 URL 的前缀(例如 /api/books/
),BookViewSet
是要注册的 ViewSet 类。basename='book'
用于生成 URL 名称 (e.g., book-list
, book-detail
)。如果 ViewSet 设置了 queryset
属性,DRF 可以自动从模型的 _meta.model_name
推断出 basename
,所以很多时候可以省略 basename
参数,除非你需要自定义它。
通过使用 Router,你无需手动为 ViewSet 的每种操作编写 URL 模式,DRF 会根据标准 RESTful 约定自动生成。这是使用 ViewSet 的一个主要驱动力。
7. 请求与响应 (Requests & Responses)
7.1 Request 对象:获取客户端数据
DRF 的 Request
对象 (rest_framework.request.Request
) 是 Django HttpRequest
对象的扩展。它提供了更灵活的方式来解析客户端发送的数据,支持各种内容类型 (如 JSON, XML, 表单数据)。
主要属性:
request.data
: 这是Request
对象最重要的属性之一。它返回解析后的请求体数据,不区分 HTTP 方法 (GET 请求的查询参数,POST/PUT/PATCH 请求的请求体数据都会被解析)。对于 JSON 数据,它会解析成 Python 字典。request.query_params
: 访问 URL 中的查询参数 (?param=value
)。
示例:
“`python
In a DRF view method (e.g., post, put)
def post(self, request, format=None):
# 从请求体中获取数据 (例如 POST 的 JSON 数据)
data = request.data
print(data) # {‘title’: ‘…’, ‘author’: ‘…’}
# 从 URL 查询参数中获取数据 (例如 /api/books/?format=json)
format_param = request.query_params.get('format')
print(format_param) # 'json' or None
# ... use data with serializer ...
“`
7.2 Response 对象:构建返回数据
DRF 的 Response
对象 (rest_framework.response.Response
) 是 Django HttpResponse
对象的扩展。它接受任意 Python 原生数据类型(如字典、列表),然后根据客户端的 Accept
头部和视图中定义的渲染器 (Renderer) 来渲染成相应的格式(默认为 JSON)。
创建 Response
对象时,通常会传入要返回的数据和可选的状态码:
“`python
from rest_framework.response import Response
from rest_framework import status
返回成功数据
return Response({‘message’: ‘Success’, ‘data’: book_serializer.data})
返回错误数据并指定状态码
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
返回成功并指定状态码
return Response(serializer.data, status=status.HTTP_201_CREATED)
返回无内容的成功响应 (如 DELETE 请求成功)
return Response(status=status.HTTP_204_NO_CONTENT)
“`
7.3 状态码的应用
在 API 设计中,使用正确的 HTTP 状态码非常重要,它们能告诉客户端请求的结果状态。DRF 提供了 rest_framework.status
模块,包含了常用的 HTTP 状态码常量,便于使用和提高代码可读性。
status.HTTP_200_OK
: 请求成功status.HTTP_201_CREATED
: 资源创建成功 (通常用于 POST)status.HTTP_204_NO_CONTENT
: 请求成功但无内容返回 (通常用于 DELETE, PUT, PATCH)status.HTTP_400_BAD_REQUEST
: 客户端发送的数据无效status.HTTP_401_UNAUTHORIZED
: 未认证status.HTTP_403_FORBIDDEN
: 已认证但无权限status.HTTP_404_NOT_FOUND
: 资源不存在status.HTTP_500_INTERNAL_SERVER_ERROR
: 服务器内部错误
始终在 Response
中显式或隐式(默认 200 OK)地设置正确的状态码。
8. 权限与认证 (Authentication & Permissions)
保护你的 API 不被未经授权的访问是至关重要的。DRF 提供了灵活的认证和权限系统。
8.1 为何需要认证和权限?
- 认证 (Authentication): 确定发出请求的客户端/用户是谁。它回答“你是谁?”的问题。常见的认证方式有基于 Session、Token、OAuth 等。
- 权限 (Permissions): 确定已认证的用户是否有权执行请求的操作 (如访问某个资源、修改某个数据)。它回答“你能做什么?”的问题。
认证总是发生在权限检查之前。只有确定了请求者的身份,才能判断他是否有相应的权限。
8.2 认证 (Authentication):你是谁?
你可以在全局 settings.py
或在具体的视图类中设置认证类。
全局配置 (应用于所有视图):
“`python
settings.py
REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.SessionAuthentication’, # 用于基于 Session 的认证 (配合 Django 后台登录)
‘rest_framework.authentication.TokenAuthentication’, # 用于基于 Token 的认证
# ‘rest_framework_simplejwt.authentication.JWTAuthentication’, # 如果使用 JWT
]
}
“`
视图级配置 (只应用于该视图):
“`python
my_app/views.py
from rest_framework.views import APIView
from rest_framework.authentication import TokenAuthentication, SessionAuthentication
from rest_framework.permissions import IsAuthenticated # 权限类后面讲
class ProtectedView(APIView):
authentication_classes = [SessionAuthentication, TokenAuthentication] # 指定该视图使用的认证类
permission_classes = [IsAuthenticated] # 指定该视图使用的权限类
def get(self, request):
# request.user 会是一个 User 对象 (如果已认证) 或 AnonymousUser (如果未认证)
content = {
'user': str(request.user), # User instance
'auth': str(request.auth), # Token instance or None
}
return Response(content)
“`
SessionAuthentication
依赖于 Django 内置的 session 和 cookie,常用于与传统的基于 session 的 Web 应用集成,或者在 API 浏览器中方便测试(如果你已经登录了 Django 后台)。
TokenAuthentication
是一种更常见的 API 认证方式。用户通过登录获取一个唯一的 token,后续请求在 Authorization
头部携带这个 token (Authorization: Token <your_token>
)。你需要安装 rest_framework.authtoken
应用并运行迁移:
“`bash
settings.py
INSTALLED_APPS = [
# …
‘rest_framework’,
‘rest_framework.authtoken’, # Add this line
# …
]
“`
bash
python manage.py migrate
然后,你可以创建一个简单的视图供用户获取 Token:
“`python
my_app/views.py (add this)
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomObtainAuthToken(ObtainAuthToken):
def post(self, request, args, *kwargs):
serializer = self.serializer_class(data=request.data,
context={‘request’: request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data[‘user’]
token, created = Token.objects.get_or_create(user=user)
return Response({
‘token’: token.key,
‘user_id’: user.pk,
’email’: user.email
})
my_app/urls.py (add this to urlpatterns)
from .views import CustomObtainAuthToken
path(‘token-auth/’, CustomObtainAuthToken.as_view()),
``
/api/token-auth/` 发送 POST 请求,包含 username 和 password,如果验证通过,将收到一个包含 token 的响应。
客户端向
8.3 权限 (Permissions):你能做什么?
权限类决定了是否允许请求继续处理。它们也可以在全局或视图级别设置。
全局配置:
“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticated’, # Default: Only authenticated users can access
]
}
“`
视图级配置:
“`python
my_app/views.py (using ViewSet)
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser, IsAuthenticatedOrReadOnly
from .models import Book
from .serializers import BookSerializer
class BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
# permission_classes = [AllowAny] # 允许任何人访问
# permission_classes = [IsAuthenticated] # 只允许已认证用户访问
# permission_classes = [IsAdminUser] # 只允许管理员用户访问
permission_classes = [IsAuthenticatedOrReadOnly] # 已认证用户可读写,未认证用户只读
# 你也可以创建自定义权限类
# permission_classes = [IsAuthenticated, CustomPermission]
“`
常见的权限类:
AllowAny
: 允许任何用户访问,无论是否认证。IsAuthenticated
: 只允许已认证用户访问。IsAdminUser
: 只允许is_staff
为True
的用户访问。IsAuthenticatedOrReadOnly
: 已认证用户可以执行任何操作 (GET, POST, PUT, DELETE),未认证用户只能执行安全操作 (GET, HEAD, OPTIONS)。这非常常用。
你可以通过继承 rest_framework.permissions.BasePermission
创建自定义权限类,实现 has_permission(self, request, view)
和 has_object_permission(self, request, view, obj)
方法来定义更复杂的权限逻辑。
将认证类和权限类结合使用,你就可以构建安全可靠的 API 了。例如,使用 TokenAuthentication
+ IsAuthenticated
要求用户必须携带有效 token 才能访问,使用 TokenAuthentication
+ IsAuthenticatedOrReadOnly
要求携带 token 的用户可以修改数据,不带 token 的用户只能读取数据。
9. 进阶特性 (简要介绍)
DRF 还提供了许多其他强大的功能,这里简要介绍一些常用的:
-
分页 (Pagination): 当数据集很大时,一次性返回所有数据效率低下且占用资源。DRF 提供了多种分页方式 (如 PageNumberPagination, LimitOffsetPagination, CursorPagination),可以很方便地为列表视图添加分页功能。
“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
‘PAGE_SIZE’: 10 # 默认每页大小
}或者在视图中指定
class BookList(generics.ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
pagination_class = rest_framework.pagination.LimitOffsetPagination
``
django-filter
* **过滤与搜索 (Filtering & Searching):** 让客户端能够根据特定条件过滤或搜索资源。DRF 支持集成应用实现强大的过滤功能,也内置了简单的搜索功能 (
SearchFilter`)。“`python
settings.py
REST_FRAMEWORK = {
# …
‘DEFAULT_FILTER_BACKENDS’: [‘django_filters.rest_framework.DjangoFilterBackend’, ‘rest_framework.filters.SearchFilter’],
}安装 django-filter: pip install django-filter
添加到 INSTALLED_APPS
在视图中指定过滤和搜索字段
class BookList(generics.ListAPIView):
queryset = Book.objects.all()
serializer_class = BookSerializer
filterset_fields = [‘author’, ‘published_date’] # 允许通过 author 或 published_date 过滤
search_fields = [‘title’, ‘author’] # 允许通过 title 或 author 搜索
“`
* 限流 (Throttling): 控制客户端在一段时间内可以发出的请求次数,防止滥用。 -
测试 API: DRF 提供了
APIClient
和APITestCase
类,方便编写针对 API 的测试。 -
API 文档: DRF 可以与
drf-yasg
或django-rest-swagger
等第三方库集成,自动生成符合 OpenAPI (Swagger) 规范的交互式 API 文档。
10. 构建一个简单的 API 示例
让我们综合前面学到的知识,快速构建一个简单的 Book API:
- 创建 Django 项目和应用:
bash
django-admin startproject myapi
cd myapi
python manage.py startapp my_app -
配置 settings.py:
“`python
# myapi/settings.py
INSTALLED_APPS = [
# … default apps
‘rest_framework’,
‘rest_framework.authtoken’, # 如果需要 token 认证
‘my_app’, # 添加你的应用
]REST_FRAMEWORK = {
‘DEFAULT_AUTHENTICATION_CLASSES’: [
‘rest_framework.authentication.TokenAuthentication’,
‘rest_framework.authentication.SessionAuthentication’, # for browsable API
],
‘DEFAULT_PERMISSION_CLASSES’: [
‘rest_framework.permissions.IsAuthenticatedOrReadOnly’ # 默认权限
],
# ‘DEFAULT_PAGINATION_CLASS’: ‘rest_framework.pagination.PageNumberPagination’,
# ‘PAGE_SIZE’: 10,
# ‘DEFAULT_FILTER_BACKENDS’: [‘django_filters.rest_framework.DjangoFilterBackend’],
# ‘FILTER_REQUEST_PARAMETER’: ‘filter’, # customize filter parameter name
# ‘SEARCH_PARAM’: ‘search’, # customize search parameter name
# ‘ORDERING_PARAM’: ‘ordering’, # customize ordering parameter name
}Add at the end for browsable API login/logout links
LOGIN_URL = ‘/api-auth/login/’
LOGOUT_URL = ‘/api-auth/logout/’
3. **定义模型 (models.py):** (同上文 Book 模型)
pythonmy_app/models.py
from django.db import models
class Book(models.Model):
title = models.CharField(max_length=100)
author = models.CharField(max_length=100)
published_date = models.DateField()
isbn = models.CharField(max_length=13, unique=True)def __str__(self): return self.title
4. **定义序列化器 (serializers.py):** (同上文 BookSerializer)
pythonmy_app/serializers.py
from rest_framework import serializers
from .models import Bookclass BookSerializer(serializers.ModelSerializer):
class Meta:
model = Book
fields = [‘id’, ‘title’, ‘author’, ‘published_date’, ‘isbn’]
5. **定义视图 (views.py):** (使用 ViewSet)
pythonmy_app/views.py
from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticatedOrReadOnly # 导入权限类
from .models import Book
from .serializers import BookSerializerclass BookViewSet(viewsets.ModelViewSet):
queryset = Book.objects.all()
serializer_class = BookSerializer
permission_classes = [IsAuthenticatedOrReadOnly] # 应用权限类
6. **配置 URLs (my_app/urls.py):** (使用 Router)
pythonmy_app/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import BookViewSetfrom .views import CustomObtainAuthToken # 如果需要 token 认证视图
router = DefaultRouter()
router.register(r’books’, BookViewSet) # basename 可以省略,DRF 会推断urlpatterns = [
path(”, include(router.urls)),
# path(‘token-auth/’, CustomObtainAuthToken.as_view()), # token 认证 URL
]
7. **配置项目 URLs (myapi/urls.py):**
pythonmyapi/urls.py
from django.contrib import admin
from django.urls import path, includefrom rest_framework.authtoken import views # 如果使用 DRF 内置的 ObtainAuthToken
urlpatterns = [
path(‘admin/’, admin.site.urls),
path(‘api/’, include(‘my_app.urls’)), # 包含你的 API URLs
# path(‘api-auth/’, include(‘rest_framework.urls’)), # 用于在 API 浏览器中显示登录/退出链接 (SessionAuthentication)
# path(‘api-token-auth/’, views.obtain_auth_token) # 如果使用 DRF 内置的 ObtainAuthToken 视图
]
8. **运行数据库迁移:**
bash
python manage.py makemigrations
python manage.py migrate
9. **创建超级用户 (如果需要测试认证/权限):**
bash
python manage.py createsuperuser
10. **运行开发服务器:**
bash
python manage.py runserver
“`
现在,你可以在浏览器中访问 http://127.0.0.1:8000/api/books/
。由于你可能没有登录(默认使用了 SessionAuthentication 配合 browsable API),你只能看到图书列表(GET 请求),尝试 POST/PUT/DELETE 会被拒绝(403 Forbidden),因为你没有写权限。如果你在浏览器中登录了 Django 后台 (http://127.0.0.1:8000/admin/
),然后再次访问 API 地址,你会发现你可以进行写操作了(因为 SessionAuthentication 认证了你)。
如果你配置了 TokenAuthentication
和 Token 获取视图,你可以使用 curl
或 Postman 等工具测试,在请求头部加上 Authorization: Token <你的token>
来进行认证。
11. 总结与后续学习方向
恭喜你!你已经从零开始了解并实践了 Django REST Framework 的核心概念:序列化器、视图(APIView, Generic Views, ViewSets)、URLs 和 Routers、Request/Response 对象,以及重要的安全特性——认证和权限。
这仅仅是 DRF 功能的冰山一角。作为下一步,你可以继续学习和探索:
- 更高级的序列化器: 嵌套序列化器、定制字段、自定义验证。
- 自定义权限和认证类: 实现更复杂的业务逻辑。
- 使用过滤和搜索后台: 实现更强大的数据查询功能。
- 配置分页: 根据你的需求调整分页样式和参数。
- 限流策略: 保护你的 API 免受过载。
- 异常处理: 定制 API 的错误响应。
- 编写 API 测试: 确保你的 API 按预期工作。
- 生成 API 文档: 使用
drf-yasg
等工具为你的 API 生成交互式文档。 - 跨域资源共享 (CORS): 如果你的前端运行在不同的域名/端口,需要配置 CORS。
- 不同的认证方式: JWT (JSON Web Tokens) 是另一种流行的 API 认证方式。
推荐学习资源:
- DRF 官方文档 (必读): 它是最权威、最详细的资源。虽然初看可能觉得信息量大,但随着你对核心概念的理解加深,你会发现它非常有价值。
www.django-rest-framework.org
- Real Python DRF 教程: 提供了一系列高质量的 DRF 教程,非常适合进阶学习。
- 在线课程: Udemy, Coursera, Bilibili 等平台有许多关于 Django 和 DRF 的课程。
- GitHub 上的开源项目: 学习其他开发者如何使用 DRF 构建实际应用。
记住,最好的学习方式是实践。多动手写代码,尝试构建不同的 API,遇到问题时查阅文档和搜索解决方案。DRF 强大的功能和灵活性将极大地提升你构建 Web API 的效率和体验。祝你在 DRF 的学习旅程中一切顺利!