Django REST Framework API 开发

小飞兽 Django 6 次阅读 2026-07-29

Django REST Framework(DRF)是 Django 最流行的 API 开发框架,它提供了序列化、视图集、路由生成、认证等全套解决方案。本文详细介绍如何使用 DRF 构建专业 API。

安装与配置

pip install djangorestframework

settings.py

INSTALLED_APPS = [ ... "rest_framework", "rest_framework.authtoken", # Token 认证 "blog", ]

REST_FRAMEWORK = {
"DEFAULT_AUTHENTICATION_CLASSES": [
"rest_framework.authentication.SessionAuthentication",
"rest_framework.authentication.TokenAuthentication",
],
"DEFAULT_PERMISSION_CLASSES": [
"rest_framework.permissions.IsAuthenticatedOrReadOnly",
],
"DEFAULT_PAGINATION_CLASS": "rest_framework.pagination.PageNumberPagination",
"PAGE_SIZE": 20,
"DEFAULT_RENDERER_CLASSES": [
"rest_framework.renderers.JSONRenderer",
"rest_framework.renderers.BrowsableAPIRenderer",
],
"DEFAULT_FILTER_BACKENDS": [
"rest_framework.filters.SearchFilter",
"rest_framework.filters.OrderingFilter",
],
}

序列化器

# blog/serializers.py
from rest_framework import serializers
from django.contrib.auth import get_user_model
from .models import Article, Category, Tag

User = get_user_model()

class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ["id", "name", "slug"]

class CategorySerializer(serializers.ModelSerializer):
article_count = serializers.SerializerMethodField()

class Meta:
model = Category
fields = ["id", "name", "slug", "article_count"]

def get_article_count(self, obj):
return obj.articles.count()

class AuthorSerializer(serializers.ModelSerializer):
class Meta:
model = User
fields = ["id", "username", "email", "avatar"]

class ArticleListSerializer(serializers.ModelSerializer):
"""文章列表序列化器(精简)"""
author = serializers.CharField(source="author.username", read_only=True)
category = serializers.CharField(source="category.name", read_only=True)

class Meta:
model = Article
fields = ["id", "title", "slug", "author", "category", "views", "created_at"]

class ArticleDetailSerializer(serializers.ModelSerializer):
"""文章详情序列化器(完整)"""
author = AuthorSerializer(read_only=True)
category = CategorySerializer(read_only=True)
tags = TagSerializer(many=True, read_only=True)
tag_ids = serializers.ListField(write_only=True, required=False)

class Meta:
model = Article
fields = [
"id", "title", "slug", "content", "excerpt",
"author", "category", "tags", "tag_ids",
"views", "is_published", "created_at", "updated_at"
]
read_only_fields = ["views", "author", "created_at", "updated_at"]

def create(self, validated_data):
tag_ids = validated_data.pop("tag_ids", [])
article = Article.objects.create(**validated_data)
if tag_ids:
article.tags.set(tag_ids)
return article

def update(self, instance, validated_data):
tag_ids = validated_data.pop("tag_ids", None)
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
if tag_ids is not None:
instance.tags.set(tag_ids)
return instance

视图与视图集

# blog/views.py
from rest_framework import viewsets, generics, filters, pagination
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, AllowAny, IsAdminUser
from django_filters.rest_framework import DjangoFilterBackend

from .models import Article, Category
from .serializers import ArticleListSerializer, ArticleDetailSerializer, CategorySerializer

class ArticlePagination(pagination.PageNumberPagination):
page_size = 20
page_size_query_param = "page_size"
max_page_size = 100

class ArticleViewSet(viewsets.ModelViewSet):
"""文章视图集:自动提供 list/retrieve/create/update/destroy 操作"""
queryset = Article.objects.filter(is_published=True)
serializer_class = ArticleListSerializer
pagination_class = ArticlePagination
filter_backends = [filters.SearchFilter, filters.OrderingFilter]
search_fields = ["title", "content"]
ordering_fields = ["created_at", "views", "title"]
ordering = ["-created_at"]

def get_serializer_class(self):
if self.action == "retrieve":
return ArticleDetailSerializer
return ArticleListSerializer

def get_permissions(self):
if self.action in ["list", "retrieve"]:
return [AllowAny()]
return [IsAuthenticated()]

def retrieve(self, request, *args, **kwargs):
instance = self.get_object()
instance.views += 1
instance.save(update_fields=["views"])
serializer = self.get_serializer(instance)
return Response(serializer.data)

@action(detail=False, methods=["get"])
def by_category(self, request, pk=None):
"""自定义动作:按分类获取文章"""
category_id = request.query_params.get("category_id")
articles = self.queryset.filter(category_id=category_id)
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)

@action(detail=True, methods=["post"], permission_classes=[IsAuthenticated])
def publish(self, request, pk=None):
"""发布文章"""
article = self.get_object()
article.is_published = True
article.save(update_fields=["is_published"])
return Response({"status": "published"})

URL 路由

# blog/urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from . import views

router = DefaultRouter()
router.register("articles", views.ArticleViewSet, basename="article")
router.register("categories", views.CategoryViewSet, basename="category")

urlpatterns = [
path("", include(router.urls)),
]

自动生成的路由:

GET /articles/ → list

POST /articles/ → create

GET /articles/{id}/ → retrieve

PUT /articles/{id}/ → update

DELETE /articles/{id}/ → destroy

GET /articles/{id}/publish/ → custom action

GET /articles/by_category/ → custom action</code></pre><h2>认证方式</h2><pre><code># settings.py 配置多种认证方式

REST_FRAMEWORK = { "DEFAULT_AUTHENTICATION_CLASSES": [ "rest_framework.authentication.SessionAuthentication", "rest_framework.authentication.TokenAuthentication", "rest_framework.authentication.BasicAuthentication", # "rest_framework.authentication.JWTAuthentication", # 需安装 djangorestframework-simplejwt ], }

使用 TokenAuthentication 时需要创建 token

from rest_framework.authtoken.models import Token

登录时返回 token

@api_view(["POST"]) def obtain_token(request): user = authenticate( username=request.data.get("username"), password=request.data.get("password") ) if user: token, _ = Token.objects.get_or_create(user=user) return Response({"token": token.key}) return Response({"error": "认证失败"}, status=401)

请求时带上 token

Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b</code></pre><h2>常见问题</h2><ul><li><strong>Q: 序列化器的 SerializerMethodField 和普通字段有什么区别?</strong><br>A:普通字段直接映射模型字段;SerializerMethodField 通过 get_xxx 方法自定义计算逻辑,用于需要聚合、跨表查询或格式转换的场景。</li><li><strong>Q: ViewSet 和 APIView 怎么选?</strong><br>A:ModelViewSet 提供开箱即用的 CRUD,适合标准的资源管理接口;GenericAPIView + Mixins 提供部分功能;APIView 则是最底层的类,适合完全自定义的逻辑。</li><li><strong>Q: DRF 的分页和普通 Django 分页有何区别?</strong><br>A:DRF 的分页输出格式为 { "count": 100, "next": "url", "previous": "url", "results": [...] },这是标准的分页 API 格式,客户端容易处理。</li><li><strong>Q: 如何在 DRF 中处理文件上传?</strong><br>A:使用 DRF 的 FileField 或 ImageField 序列化器,配合 multipart/form-data 格式提交,DRF 会自动处理 request.FILES。</li></ul><h2>延伸阅读</h2><ul><li><a href="https://www.django-rest-framework.org/tutorial/quickstart/">DRF 快速入门教程</a></li><li><a href="https://www.django-rest-framework.org/api-guide/viewsets/">DRF ViewSets 官方文档</a></li><li>Django REST Framework 认证与权限深度解析</li></ul>