Python
使用 DRF 开发 RESTful API
发布于 2026年7月23日
使用 DRF 开发 RESTful API
Django REST framework(DRF)为 Django 增加序列化、API 视图、认证、权限、分页和可浏览 API。本篇为留言项目提供一套带对象权限的 JSON API。
一、安装与注册
python -m pip install djangorestframework
settings.py:
INSTALLED_APPS = [
# Django 与项目应用
"rest_framework",
]
建议把 API 代码放在应用内部的 api/ 子包,或在规模较小时使用 serializers.py 和 api_views.py。
二、Serializer
Serializer 负责模型对象与 JSON 数据之间的转换,同时承担输入校验。
# notes/serializers.py
from rest_framework import serializers
from .models import Message
class MessageSerializer(serializers.ModelSerializer):
owner = serializers.CharField(source="owner.username", read_only=True)
class Meta:
model = Message
fields = [
"id",
"owner",
"name",
"content",
"status",
"created_at",
"updated_at",
]
read_only_fields = ["id", "owner", "created_at", "updated_at"]
def validate_content(self, value):
value = value.strip()
if len(value) < 10:
raise serializers.ValidationError("内容至少需要 10 个字符。")
return value
与 ModelForm 一样,应显式列出字段,并把 owner、时间等服务端字段设为只读。
三、ViewSet 与 Router
# notes/api_views.py
from django.db.models import Q
from rest_framework import permissions, viewsets
from .models import Message
from .serializers import MessageSerializer
class MessageViewSet(viewsets.ModelViewSet):
serializer_class = MessageSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
def get_queryset(self):
queryset = Message.objects.select_related("owner")
if self.request.user.is_authenticated:
return queryset.filter(
Q(status=Message.Status.PUBLISHED) | Q(owner=self.request.user)
).distinct()
return queryset.filter(status=Message.Status.PUBLISHED)
def perform_create(self, serializer):
serializer.save(owner=self.request.user)
路由:
# notes/api_urls.py
from rest_framework.routers import DefaultRouter
from .api_views import MessageViewSet
router = DefaultRouter()
router.register("messages", MessageViewSet, basename="message")
urlpatterns = router.urls
项目根路由:
path("api/", include("notes.api_urls")),
ModelViewSet 默认提供列表、创建、详情、完整更新、部分更新和删除。业务不允许某些操作时,应使用更小的 Generic View 或组合 Mixin,而不是暴露后再靠前端隐藏。
四、对象级权限
实现“所有人可读,只有作者可修改”:
# notes/permissions.py
from rest_framework import permissions
class IsOwnerOrReadOnly(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in permissions.SAFE_METHODS:
return True
return obj.owner == request.user
视图中:
permission_classes = [
permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,
]
对象权限通常在详情操作时检查。列表接口还需要在 get_queryset() 中限制可见数据,不能期待对象权限自动逐条过滤列表。
五、分页、搜索与排序
settings.py:
REST_FRAMEWORK = {
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
"DEFAULT_FILTER_BACKENDS": [
"rest_framework.filters.SearchFilter",
"rest_framework.filters.OrderingFilter",
],
}
ViewSet:
search_fields = ["name", "content", "owner__username"]
ordering_fields = ["created_at", "updated_at"]
ordering = ["-created_at"]
请求示例:
GET /api/messages/?search=django&ordering=-created_at&page=2
复杂字段筛选可引入 django-filter,并明确允许筛选的字段。
六、认证选择
SessionAuthentication:同域网页和可浏览 API,配合 CSRF。- Token/JWT:移动端或独立前端常用,需规划刷新、撤销、存储和过期策略。
- OAuth2/OIDC:接入统一身份平台或第三方登录。
不要自己发明密码哈希、签名和令牌协议。无论何种认证,生产 API 都应使用 HTTPS。
可浏览 API 登录路由:
path("api-auth/", include("rest_framework.urls")),
七、自定义 Action
from rest_framework import permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
@action(
detail=True,
methods=["post"],
permission_classes=[permissions.IsAuthenticated],
)
def publish(self, request, pk=None):
message = self.get_object()
if message.owner != request.user:
return Response(
{"detail": "无权发布。"},
status=status.HTTP_403_FORBIDDEN,
)
message.status = Message.Status.PUBLISHED
message.save(update_fields=["status", "updated_at"])
return Response(self.get_serializer(message).data)
自定义 Action 适合发布、归档、取消等不属于标准 CRUD 的资源动作。不要把所有 RPC 操作都堆进同一个 ViewSet。
八、状态码与错误
200 OK:成功读取或更新。201 Created:创建成功。204 No Content:删除成功且无响应体。400 Bad Request:输入校验失败。401 Unauthorized:未通过认证。403 Forbidden:已识别身份但无权限。404 Not Found:资源不存在或不应向当前用户暴露。429 Too Many Requests:请求过于频繁。
API 错误结构应保持稳定,便于前端统一展示和监控。
九、API 测试
from django.contrib.auth import get_user_model
from rest_framework import status
from rest_framework.test import APITestCase
User = get_user_model()
class MessageAPITests(APITestCase):
def test_authenticated_user_can_create_message(self):
user = User.objects.create_user("api-user", password="pass-12345")
self.client.force_authenticate(user)
response = self.client.post("/api/messages/", {
"name": "API 留言",
"content": "这是一条通过 API 创建的留言",
"status": "published",
})
self.assertEqual(response.status_code, status.HTTP_201_CREATED)
self.assertEqual(response.data["owner"], "api-user")
十、本篇检查清单
- 能用 Serializer 校验并转换数据。
- 能用 ViewSet 与 Router 创建标准资源 API。
- 能同时实施视图级和对象级权限。
- 能配置分页、搜索和排序。
- 理解 Session、Token/JWT 和 OAuth 的适用场景。
上一篇:测试、调试与日志 | 下一篇:缓存、性能优化与异步任务