#Django REST框架与API开发
#课程目标
- 理解Django REST Framework (DRF) 的核心概念
- 掌握序列化器的定义和使用
- 学会创建和管理API端点
- 了解API认证和权限控制
#Django REST Framework概述
Django REST Framework (DRF) 是一个基于Django构建的、成熟的Web API工具包。它可以帮你快速实现RESTful风格的接口,同时内置了开发生产级API所需的全套工具:序列化、可浏览界面、认证权限、限流、内容协商,以及完善的文档生态。
#核心优势特性:
- 强大的序列化系统:无缝对接Django ORM,支持嵌套、自定义字段、数据校验
- 友好的可浏览Web界面:无需Postman即可调试接口
- 开箱即用的认证权限:Token、Session、JWT、OAuth2可选,还支持自定义
- 灵活的限流过滤:IP限流、API限流、DjangoFilterBackend过滤
- 丰富的插件生态:缓存、文档、分页、搜索等扩展应有尽有
#安装和配置
#快速安装
用pip直接安装即可,同时注意与你的Django版本兼容:
pip install djangorestframework#基础settings.py配置
将DRF加入INSTALLED_APPS,并配置默认的认证、权限、渲染器等:
# settings.py
INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'rest_framework', # 必须的DRF核心
'myapp', # 你的业务应用
]
# DRF全局配置
REST_FRAMEWORK = {
# 全局认证方式:优先Token,再Session(方便可浏览界面登录)
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.TokenAuthentication',
'rest_framework.authentication.SessionAuthentication',
],
# 全局权限:默认需要登录,部分接口可覆盖
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
],
# 全局分页:PageNumberPagination(经典页码),每页20条
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 20,
# 全局渲染器:JSON(生产)+ BrowsableAPI(开发调试)
'DEFAULT_RENDERER_CLASSES': [
'rest_framework.renderers.JSONRenderer',
'rest_framework.renderers.BrowsableAPIRenderer',
],
}#序列化器(Serializers)
序列化器是DRF的核心转换层:负责把Django ORM对象→JSON/XML/HTML,或者反过来把前端提交的请求数据→Python对象/ORM模型实例。
#ModelSerializer(推荐首选)
不用手动写字段映射,直接从Django Model自动生成,还能复用Model的字段验证逻辑,只需要自定义额外字段或复杂校验即可:
# serializers.py
from rest_framework import serializers
from .models import Article, Category
# 先写子序列化器,后面可以嵌套
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name', 'slug', 'created_at']
read_only_fields = ['slug', 'created_at'] # 这些字段只能后端生成,不能前端提交
class ArticleSerializer(serializers.ModelSerializer):
# 自定义额外字段:从关联对象获取
author_name = serializers.CharField(source='author.username', read_only=True)
category_name = serializers.CharField(source='category.name', read_only=True)
# SerializerMethodField:完全自定义获取逻辑
tags_list = serializers.SerializerMethodField()
class Meta:
model = Article
fields = [
'id', 'title', 'content', 'summary', 'author', 'author_name',
'category', 'category_name', 'status', 'tags', 'tags_list',
'created_at', 'updated_at', 'view_count'
]
read_only_fields = ['author', 'created_at', 'updated_at', 'view_count']
# SerializerMethodField对应的get_xxx方法
def get_tags_list(self, obj):
"""把标签对象列表转换为标签名列表"""
return [tag.name for tag in obj.tags.all()]
# 单个字段验证:validate_<field_name>
def validate_title(self, value):
"""验证标题长度"""
if len(value) < 5:
raise serializers.ValidationError("标题至少需要5个字符")
return value
def validate_content(self, value):
"""验证内容长度"""
if len(value) < 10:
raise serializers.ValidationError("内容至少需要10个字符")
return value
# 重写create方法:处理多对多标签
def create(self, validated_data):
"""自定义文章创建逻辑,因为标签是多对多不能直接create"""
tags_data = validated_data.pop('tags', [])
article = Article.objects.create(**validated_data)
if tags_data:
article.tags.set(tags_data)
return article
# 重写update方法:处理多对多标签
def update(self, instance, validated_data):
"""自定义文章更新逻辑"""
tags_data = validated_data.pop('tags', None)
# 更新普通字段
for attr, value in validated_data.items():
setattr(instance, attr, value)
instance.save()
# 只有前端提交了tags才更新
if tags_data is not None:
instance.tags.set(tags_data)
return instance#嵌套序列化器(详情页专用)
详情页通常需要显示更完整的关联数据,比如作者信息、分类详情、已审核的评论,这时候可以用嵌套的子序列化器:
class ArticleDetailSerializer(serializers.ModelSerializer):
# StringRelatedField:直接显示关联对象的__str__()
author = serializers.StringRelatedField(read_only=True)
tags = serializers.StringRelatedField(many=True, read_only=True)
# 嵌套完整的子序列化器
category = CategorySerializer(read_only=True)
comments = serializers.SerializerMethodField()
class Meta:
model = Article
fields = [
'id', 'title', 'content', 'summary', 'author', 'category',
'status', 'tags', 'comments', 'created_at', 'updated_at', 'view_count'
]
def get_comments(self, obj):
"""只返回已审核的评论"""
from myapp.serializers import CommentSerializer # 避免循环导入
comments = obj.comments.filter(is_approved=True)
return CommentSerializer(comments, many=True).data#API视图开发
DRF提供了3种视图编写方式,从简单到复杂灵活选择:
#1. 基于函数的视图(@api_view)
适合简单的、逻辑不重复的接口,用装饰器快速实现:
# views.py
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework import status
from rest_framework.permissions import IsAuthenticated, AllowAny
from .models import Article
from .serializers import ArticleSerializer, ArticleDetailSerializer
@api_view(['GET'])
@permission_classes([AllowAny])
def article_list(request):
"""获取已发布的文章列表(支持简单手动分页)"""
articles = Article.objects.filter(status='published').order_by('-created_at')
# 手动分页(推荐全局或视图级配置自动分页,这里仅演示)
from rest_framework.pagination import PageNumberPagination
paginator = PageNumberPagination()
paginator.page_size = 10
result_page = paginator.paginate_queryset(articles, request)
serializer = ArticleSerializer(result_page, many=True)
return paginator.get_paginated_response(serializer.data)
@api_view(['GET'])
@permission_classes([AllowAny])
def article_detail(request, pk):
"""获取文章详情(自动增加浏览量)"""
try:
article = Article.objects.get(pk=pk, status='published')
article.view_count += 1
article.save(update_fields=['view_count']) # 只更新浏览量,性能更好
serializer = ArticleDetailSerializer(article)
return Response(serializer.data)
except Article.DoesNotExist:
return Response({'error': '文章不存在'}, status=status.HTTP_404_NOT_FOUND)
@api_view(['POST'])
@permission_classes([IsAuthenticated])
def create_article(request):
"""认证用户创建文章"""
serializer = ArticleSerializer(data=request.data)
if serializer.is_valid():
serializer.save(author=request.user) # 自动关联当前登录用户
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)#2. 基于类的通用视图(generics)
适合CRUD标准接口,减少重复代码,还能细粒度覆盖方法:
from rest_framework import generics, permissions, status
from rest_framework.response import Response
from django.shortcuts import get_object_or_404
class ArticleListCreateView(generics.ListCreateAPIView):
"""文章列表+创建接口(通用视图自动处理分页、权限等)"""
# 注意:get_queryset()方法会覆盖queryset属性,这里可以留空或写默认
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [permissions.IsAuthenticatedOrReadOnly] # 读允许所有人,写需要登录
# 自定义查询逻辑:支持搜索、分类筛选、标签筛选
def get_queryset(self):
queryset = Article.objects.filter(status='published')
search = self.request.query_params.get('search', '')
if search:
queryset = queryset.filter(title__icontains=search)
category = self.request.query_params.get('category', '')
if category:
queryset = queryset.filter(category__name=category)
tag = self.request.query_params.get('tag', '')
if tag:
queryset = queryset.filter(tags__name=tag)
return queryset.order_by('-created_at')
# 自定义创建逻辑:自动关联当前登录用户
def perform_create(self, serializer):
serializer.save(author=self.request.user)
class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
"""文章详情+更新+删除接口(通用视图自动处理单个对象)"""
queryset = Article.objects.all()
# 读用详情序列化器,写用普通序列化器
def get_serializer_class(self):
if self.request.method == 'GET':
return ArticleDetailSerializer
return ArticleSerializer
# 自定义权限:读允许所有人,写需要作者或管理员
def get_permissions(self):
if self.request.method in ['PUT', 'PATCH', 'DELETE']:
return [permissions.IsAuthenticated()]
return [permissions.AllowAny()]
# 检查对象级权限
def check_object_permissions(self, request, obj):
super().check_object_permissions(request, obj)
if request.method in ['PUT', 'PATCH', 'DELETE']:
if obj.author != request.user and not request.user.is_staff:
self.permission_denied(
request,
message='您没有权限执行此操作',
code='permission_denied'
)#视图集(ViewSets)
视图集是DRF的最高级封装,把CRUD的所有接口(list、create、retrieve、update、partial_update、destroy)整合到一个类里,还能自动生成URL路由,适合复杂的、需要自定义额外接口的业务:
from rest_framework import viewsets, permissions, status
from rest_framework.decorators import action
from rest_framework.response import Response
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from .models import Article
from .serializers import ArticleSerializer, ArticleDetailSerializer
class ArticleViewSet(viewsets.ModelViewSet):
"""文章视图集(支持所有CRUD+自定义接口+自动路由)"""
queryset = Article.objects.all()
permission_classes = [permissions.IsAuthenticatedOrReadOnly]
# 内置过滤、搜索、排序
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['status', 'category', 'author']
search_fields = ['title', 'content', 'tags__name']
ordering_fields = ['created_at', 'view_count', 'like_count']
ordering = ['-created_at']
# 动态选择序列化器
def get_serializer_class(self):
if self.action == 'retrieve':
return ArticleDetailSerializer
return ArticleSerializer
# 自定义查询逻辑:普通用户只能看已发布,管理员看所有
def get_queryset(self):
queryset = super().get_queryset()
if not self.request.user.is_staff:
queryset = queryset.filter(status='published')
return queryset
# 自定义额外接口:detail=True表示针对单个对象,url会变成/articles/{pk}/like/
@action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
def like(self, request, pk=None):
"""点赞文章"""
article = self.get_object()
article.like_count += 1
article.save(update_fields=['like_count'])
return Response({'status': 'liked', 'likes': article.like_count})
@action(detail=True, methods=['post'], permission_classes=[permissions.IsAuthenticated])
def unlike(self, request, pk=None):
"""取消点赞"""
article = self.get_object()
if article.like_count > 0:
article.like_count -= 1
article.save(update_fields=['like_count'])
return Response({'status': 'unliked', 'likes': article.like_count})
# 自定义额外接口:detail=False表示针对整个集合,url会变成/articles/my_articles/
@action(detail=False, methods=['get'])
def my_articles(self, request):
"""获取当前用户的全部文章"""
if not request.user.is_authenticated:
return Response({'error': '请先登录'}, status=status.HTTP_401_UNAUTHORIZED)
articles = self.queryset.filter(author=request.user)
serializer = self.get_serializer(articles, many=True)
return Response(serializer.data)#自动生成URL路由
用DefaultRouter自动生成视图集的所有URL,包括自定义接口:
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from .views import ArticleViewSet
router = DefaultRouter()
router.register(r'articles', ArticleViewSet, basename='article')
urlpatterns = [
path('', include(router.urls)),
]#课程总结
本节课我们系统学习了Django REST Framework的核心能力:
- 序列化器:作为核心转换层,处理数据的序列化、反序列化、校验
- 视图开发:三种视图方式(函数→通用类→视图集)灵活应对不同复杂度的接口
- 认证权限:支持全局/视图级配置,还能自定义对象级权限
- 过滤分页排序:内置工具快速实现常用功能
- 自动生成文档和路由:提升开发效率
掌握了DRF,你就能快速构建出符合RESTful规范的生产级Web API,是开发前后端分离应用的必备技能!

