Django REST Framework 指南
使用 DRF 构建 REST API:序列化器、基于类的视图、ViewSets、路由器、JWT 认证和自定义权限。
1. 序列化器
from rest_framework import serializers
class ArticleSerializer(serializers.ModelSerializer):
author_name = serializers.CharField(source="author.get_full_name", read_only=True)
word_count = serializers.SerializerMethodField()
class Meta:
model = Article
fields = ["id", "title", "slug", "content", "author_name", "word_count", "created_at"]
read_only_fields = ["slug", "created_at"]
def get_word_count(self, obj):
return len(obj.content.split())
def validate_title(self, value):
if len(value) < 5:
raise serializers.ValidationError("标题至少需要 5 个字符。")
return value
2. ViewSets 与路由器
from rest_framework import viewsets, permissions
from rest_framework.decorators import action
from rest_framework.response import Response
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.select_related("author")
serializer_class = ArticleSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
search_fields = ["title", "content"]
ordering = ["-created_at"]
def perform_create(self, serializer):
serializer.save(author=self.request.user)
@action(detail=True, methods=["post"])
def publish(self, request, pk=None):
article = self.get_object()
article.status = "published"
article.save(update_fields=["status"])
return Response({"status": "published"})
# urls.py
from rest_framework.routers import DefaultRouter
router = DefaultRouter()
router.register("articles", ArticleViewSet)
urlpatterns = router.urls
3. 认证与权限
from rest_framework.permissions import BasePermission, SAFE_METHODS
class IsOwnerOrReadOnly(BasePermission):
def has_object_permission(self, request, view, obj):
if request.method in SAFE_METHODS:
return True
return obj.author == request.user
# settings.py
REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework_simplejwt.authentication.JWTAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly",
],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
}
4. SimpleJWT
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenSerializer(TokenObtainPairSerializer):
@classmethod
def get_token(cls, user):
token = super().get_token(user)
token["name"] = user.get_full_name()
token["email"] = user.email
token["role"] = user.role
return token