第14章:API开发
14.1 Django REST Framework入门
DRF安装配置
Django REST Framework (DRF) 是一个强大而灵活的工具包,用于构建Web API。
安装和基本配置:
bash
# 安装DRF
pip install djangorestframework
# 可选:安装API文档工具
pip install coreapi
pip install pyyamlpython
# settings.py
INSTALLED_APPS = [
# ...
'rest_framework',
'rest_framework.authtoken', # 如果使用Token认证
]
# DRF配置
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': [
'django_filters.rest_framework.DjangoFilterBackend',
'rest_framework.filters.SearchFilter',
'rest_framework.filters.OrderingFilter',
],
}
# 如果使用Token认证,需要运行迁移
# python manage.py migrate序列化器
序列化器用于在复杂数据类型(如查询集和模型实例)和Python原生数据类型之间进行转换:
python
# serializers.py
from rest_framework import serializers
from .models import Article, Category, Tag, Comment
class CategorySerializer(serializers.ModelSerializer):
class Meta:
model = Category
fields = ['id', 'name', 'slug', 'description']
class TagSerializer(serializers.ModelSerializer):
class Meta:
model = Tag
fields = ['id', 'name', 'slug']
class CommentSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
class Meta:
model = Comment
fields = ['id', 'author', 'content', 'created_at']
read_only_fields = ['author', 'created_at']
class ArticleSerializer(serializers.ModelSerializer):
author = serializers.StringRelatedField(read_only=True)
category = CategorySerializer(read_only=True)
tags = TagSerializer(many=True, read_only=True)
comments = CommentSerializer(many=True, read_only=True)
comment_count = serializers.SerializerMethodField()
class Meta:
model = Article
fields = [
'id', 'title', 'slug', 'author', 'category', 'tags',
'content', 'excerpt', 'featured_image', 'status',
'view_count', 'created_at', 'updated_at', 'published_at',
'comments', 'comment_count'
]
read_only_fields = ['author', 'view_count', 'created_at', 'updated_at', 'published_at']
def get_comment_count(self, obj):
return obj.comments.filter(is_approved=True).count()
# 嵌套序列化器示例
class ArticleListSerializer(serializers.ModelSerializer):
"""用于列表展示的简化序列化器"""
author = serializers.StringRelatedField()
category = serializers.StringRelatedField()
class Meta:
model = Article
fields = [
'id', 'title', 'slug', 'author', 'category',
'excerpt', 'featured_image', 'view_count',
'created_at', 'published_at'
]
# 自定义序列化器字段
class CustomArticleSerializer(serializers.ModelSerializer):
days_since_published = serializers.SerializerMethodField()
is_popular = serializers.SerializerMethodField()
class Meta:
model = Article
fields = '__all__'
read_only_fields = ['author']
def get_days_since_published(self, obj):
if obj.published_at:
from django.utils import timezone
return (timezone.now() - obj.published_at).days
return None
def get_is_popular(self, obj):
return obj.view_count > 1000API视图
DRF提供了多种方式来创建API视图:
python
# views.py
from rest_framework import generics, viewsets, status
from rest_framework.decorators import api_view, permission_classes
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from django_filters.rest_framework import DjangoFilterBackend
from rest_framework.filters import SearchFilter, OrderingFilter
from .models import Article, Category, Tag
from .serializers import ArticleSerializer, ArticleListSerializer, CategorySerializer
# 基于函数的视图
@api_view(['GET', 'POST'])
@permission_classes([IsAuthenticatedOrReadOnly])
def article_list(request):
if request.method == 'GET':
articles = Article.objects.filter(status='published')
serializer = ArticleListSerializer(articles, many=True)
return Response(serializer.data)
elif request.method == 'POST':
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)
# 基于类的视图
class ArticleListView(generics.ListCreateAPIView):
queryset = Article.objects.filter(status='published')
serializer_class = ArticleListSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'tags', 'author']
search_fields = ['title', 'content', 'excerpt']
ordering_fields = ['created_at', 'view_count', 'published_at']
ordering = ['-created_at']
class ArticleDetailView(generics.RetrieveUpdateDestroyAPIView):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
lookup_field = 'slug'
def perform_update(self, serializer):
# 更新时检查权限
if self.request.user == serializer.instance.author:
serializer.save()
else:
raise PermissionDenied("您没有权限编辑此文章")
# ViewSet视图集
class ArticleViewSet(viewsets.ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
permission_classes = [IsAuthenticatedOrReadOnly]
filter_backends = [DjangoFilterBackend, SearchFilter, OrderingFilter]
filterset_fields = ['category', 'tags', 'author', 'status']
search_fields = ['title', 'content', 'excerpt']
ordering_fields = ['created_at', 'view_count', 'published_at']
ordering = ['-created_at']
lookup_field = 'slug'
def get_queryset(self):
if self.action == 'list':
return Article.objects.filter(status='published')
return Article.objects.all()
def get_serializer_class(self):
if self.action == 'list':
return ArticleListSerializer
return ArticleSerializer
def perform_create(self, serializer):
serializer.save(author=self.request.user)
def perform_update(self, serializer):
if self.request.user == serializer.instance.author or self.request.user.is_staff:
serializer.save()
else:
raise PermissionDenied("您没有权限编辑此文章")
# 自定义API视图
class ArticleStatsView(generics.GenericAPIView):
queryset = Article.objects.all()
def get(self, request, *args, **kwargs):
stats = {
'total_articles': Article.objects.count(),
'published_articles': Article.objects.filter(status='published').count(),
'total_views': Article.objects.aggregate(
total_views=models.Sum('view_count')
)['total_views'] or 0,
'most_popular_article': Article.objects.order_by('-view_count').first().title if Article.objects.exists() else None
}
return Response(stats)URL路由
配置API路由:
python
# urls.py
from django.urls import path, include
from rest_framework.routers import DefaultRouter
from rest_framework.authtoken.views import obtain_auth_token
from . import views
# 使用Router自动注册ViewSet
router = DefaultRouter()
router.register(r'articles', views.ArticleViewSet)
router.register(r'categories', views.CategoryViewSet)
router.register(r'tags', views.TagViewSet)
urlpatterns = [
# 函数视图
path('articles/', views.article_list, name='article-list'),
path('articles/<slug:slug>/', views.article_detail, name='article-detail'),
# 类视图
path('api/articles/', views.ArticleListView.as_view(), name='api-article-list'),
path('api/articles/<slug:slug>/', views.ArticleDetailView.as_view(), name='api-article-detail'),
# ViewSet路由
path('api/v2/', include(router.urls)),
# 统计信息
path('api/stats/', views.ArticleStatsView.as_view(), name='api-stats'),
# 认证
path('api/auth/token/', obtain_auth_token, name='api-token-auth'),
# API根路径
path('api/', views.api_root, name='api-root'),
]
# 自定义API根视图
from rest_framework.decorators import api_view
from rest_framework.response import Response
from rest_framework.reverse import reverse
@api_view(['GET'])
def api_root(request, format=None):
return Response({
'articles': reverse('api-article-list', request=request, format=format),
'categories': reverse('category-list', request=request, format=format),
'tags': reverse('tag-list', request=request, format=format),
'stats': reverse('api-stats', request=request, format=format),
})通过这些配置,你就拥有了一个功能完整的REST API,支持认证、权限控制、过滤、搜索和分页等功能。
小结
Django REST Framework入门的关键知识点:
- ✅ 掌握DRF的安装和基本配置
- ✅ 理解序列化器的作用和使用方法
- ✅ 学会使用不同类型的API视图(函数视图、类视图、ViewSet)
- ✅ 配置API路由和URL模式
- ✅ 实现认证和权限控制
DRF为Django提供了强大的API开发能力。
下一篇
我们将深入学习RESTful API设计原则。