当前位置: 首页 > news >正文

Django REST Framework 全面指南:从模型到完整API接口开发

1. Django REST Framework 简介

Django REST Framework(简称DRF)是一个强大而灵活的工具包,用于在Django中构建Web API。它提供了一系列工具和库,帮助我们快速开发符合RESTful风格的API接口。DRF的核心优势在于其简洁的代码结构、强大的序列化功能、丰富的视图类以及可扩展的认证权限系统。

在开始之前,确保已经安装DRF:

pip install djangorestframework

2. 模型定义与设计

让我们以一个简单的博客文章模型为例,展示完整的API开发流程。首先,在models.py中定义我们的Article模型:

from django.db import models
from django.contrib.auth.models import User
from django.utils import timezoneclass Article(models.Model):# 文章状态选择STATUS_CHOICES = (('draft', '草稿'),('published', '已发布'),('archived', '已归档'),)# 基础字段title = models.CharField(max_length=200, verbose_name='标题')slug = models.SlugField(max_length=200, unique=True, verbose_name='URL标识')content = models.TextField(verbose_name='内容')excerpt = models.TextField(max_length=500, blank=True, verbose_name='摘要')# 关系字段author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='articles',verbose_name='作者')# 状态与时间字段status = models.CharField(max_length=10, choices=STATUS_CHOICES, default='draft',verbose_name='状态')publish_time = models.DateTimeField(default=timezone.now, verbose_name='发布时间')created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')updated_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')# 数字字段view_count = models.PositiveIntegerField(default=0, verbose_name='浏览次数')like_count = models.PositiveIntegerField(default=0, verbose_name='点赞数')# 标记字段is_featured = models.BooleanField(default=False, verbose_name='是否推荐')class Meta:db_table = 'blog_articles'verbose_name = '文章'verbose_name_plural = '文章'ordering = ['-publish_time', '-created_time']indexes = [models.Index(fields=['status', 'publish_time']),models.Index(fields=['author', 'created_time']),]def __str__(self):return self.titledef save(self, *args, **kwargs):# 自动生成摘要(如果未提供)if not self.excerpt and self.content:self.excerpt = self.content[:150] + '...' if len(self.content) > 150 else self.contentsuper().save(*args, **kwargs)

这个模型设计考虑了实际应用场景,包含了文章管理所需的各类字段,为后续的API开发奠定了良好的数据基础。

3. 序列化器深度解析

序列化器是DRF的核心组件之一,负责数据的序列化(Python对象→JSON)和反序列化(JSON→Python对象)。让我们创建详细的序列化器:

from rest_framework import serializers
from .models import Article
from django.contrib.auth.models import User
from django.utils import timezoneclass UserSerializer(serializers.ModelSerializer):"""用户序列化器,用于嵌套显示作者信息"""full_name = serializers.CharField(source='get_full_name', read_only=True)class Meta:model = Userfields = ['id', 'username', 'full_name', 'email']read_only_fields = ['id', 'username', 'full_name', 'email']class ArticleSerializer(serializers.ModelSerializer):"""文章序列化器 - 完整版本"""# 只读字段 - 显示详细信息author_info = UserSerializer(source='author', read_only=True)status_display = serializers.CharField(source='get_status_display', read_only=True)days_since_published = serializers.SerializerMethodField(read_only=True)# 可写字段 - 用于创建和更新author = serializers.PrimaryKeyRelatedField(queryset=User.objects.all(),write_only=True,required=False  # 在创建时可以通过上下文自动设置)class Meta:model = Articlefields = ['id', 'title', 'slug', 'content', 'excerpt','author', 'author_info', 'status', 'status_display','publish_time', 'created_time', 'updated_time','view_count', 'like_count', 'is_featured','days_since_published']read_only_fields = ['id', 'author_info', 'created_time', 'updated_time','view_count', 'like_count', 'days_since_published']extra_kwargs = {'slug': {'required': False},'content': {'write_only': False},}def get_days_since_published(self, obj):"""计算文章发布至今的天数"""if obj.publish_time and obj.status == 'published':delta = timezone.now() - obj.publish_timereturn delta.daysreturn Nonedef validate_title(self, value):"""标题验证"""if len(value.strip()) < 5:raise serializers.ValidationError("标题长度不能少于5个字符")if len(value) > 200:raise serializers.ValidationError("标题长度不能超过200个字符")return value.strip()def validate_slug(self, value):"""Slug验证"""if value:import reif not re.match(r'^[a-z0-9-]+$', value):raise serializers.ValidationError("Slug只能包含小写字母、数字和连字符")# 检查slug是否唯一(排除当前实例)instance = self.instanceif instance and instance.slug == value:return valueif Article.objects.filter(slug=value).exists():raise serializers.ValidationError("该URL标识已被使用")return valuedef validate(self, attrs):"""全局验证"""# 确保草稿状态的文章没有发布时间status = attrs.get('status', self.instance.status if self.instance else 'draft')publish_time = attrs.get('publish_time')if status == 'draft' and publish_time:raise serializers.ValidationError({'publish_time': '草稿状态的文章不能设置发布时间'})# 自动生成slug(如果未提供)if not attrs.get('slug') and attrs.get('title'):from django.utils.text import slugifyattrs['slug'] = slugify(attrs['title'])return attrsdef create(self, validated_data):"""创建文章时的额外处理"""# 如果没有指定作者,使用当前用户if 'author' not in validated_data:request = self.context.get('request')if request and hasattr(request, 'user'):validated_data['author'] = request.userreturn super().create(validated_data)def update(self, instance, validated_data):"""更新文章时的额外处理"""# 记录内容变更if 'content' in validated_data and instance.content != validated_data['content']:# 这里可以添加内容变更日志passreturn super().update(instance, validated_data)class ArticleListSerializer(serializers.ModelSerializer):"""文章列表序列化器 - 简化版本,用于列表展示"""author_name = serializers.CharField(source='author.get_full_name', read_only=True)excerpt = serializers.CharField(read_only=True)comment_count = serializers.SerializerMethodField()class Meta:model = Articlefields = ['id', 'title', 'slug', 'excerpt', 'author_name','publish_time', 'view_count', 'like_count', 'is_featured', 'status', 'comment_count']read_only_fields = fieldsdef get_comment_count(self, obj):# 假设有评论模型,这里返回评论数量return 0  # 实际项目中这里应该返回真实的评论数

这个序列化器设计展示了DRF的强大功能,包括字段级别的验证、全局验证、自定义方法字段、嵌套序列化器等高级特性。

4. 视图集与视图类详细实现

DRF提供了多种视图类,从基础的APIView到功能完整的ViewSet,让我们详细实现:

from rest_framework import viewsets, status, filters
from rest_framework.decorators import action
from rest_framework.response import Response
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly, BasePermission
from django_filters.rest_framework import DjangoFilterBackend
from .models import Article
from .serializers import ArticleSerializer, ArticleListSerializerclass IsOwnerOrReadOnly(BasePermission):"""自定义权限:只允许文章的所有者编辑,其他用户只能查看"""def has_object_permission(self, request, view, obj):# 读取权限允许任何请求if request.method in ['GET', 'HEAD', 'OPTIONS']:return True# 写入权限只允许文章作者return obj.author == request.userclass ArticleViewSet(viewsets.ModelViewSet):"""文章视图集提供列表、创建、检索、更新、删除等完整操作"""queryset = Article.objects.all()permission_classes = [IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]filter_backends = [DjangoFilterBackend, filters.SearchFilter, filters.OrderingFilter]# 过滤字段filterset_fields = ['status', 'author', 'is_featured']# 搜索字段search_fields = ['title', 'content', 'excerpt']# 排序字段ordering_fields = ['publish_time', 'created_time', 'view_count', 'like_count']ordering = ['-publish_time']def get_serializer_class(self):"""根据动作选择不同的序列化器"""if self.action == 'list':return ArticleListSerializerreturn ArticleSerializerdef get_queryset(self):"""根据用户权限返回不同的查询集"""queryset = super().get_queryset()# 未认证用户只能查看已发布的文章if not self.request.user.is_authenticated:return queryset.filter(status='published')# 普通用户可以看到自己所有的文章和已发布的文章if not self.request.user.is_staff:return queryset.filter(models.Q(status='published') | models.Q(author=self.request.user))# 管理员可以看到所有文章return querysetdef perform_create(self, serializer):"""创建文章时的额外操作"""# 自动设置作者为当前用户serializer.save(author=self.request.user)# 记录创建日志# logger.info(f"User {self.request.user} created article: {serializer.data['title']}")def perform_update(self, serializer):"""更新文章时的额外操作"""instance = serializer.save()# 记录更新日志# logger.info(f"User {self.request.user} updated article: {instance.title}")def perform_destroy(self, instance):"""删除文章时的额外操作"""# 记录删除日志# logger.info(f"User {self.request.user} deleted article: {instance.title}")instance.delete()@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])def like(self, request, pk=None):"""点赞文章"""article = self.get_object()user = request.user# 这里可以添加喜欢逻辑,比如使用Through模型记录喜欢关系# 当前简单实现:直接增加计数article.like_count += 1article.save()return Response({'status': 'success','like_count': article.like_count,'message': '点赞成功'})@action(detail=True, methods=['post'], permission_classes=[IsAuthenticated])def publish(self, request, pk=None):"""发布文章(将状态改为published)"""article = self.get_object()# 检查权限if article.author != request.user and not request.user.is_staff:return Response({'error': '没有权限发布此文章'}, status=status.HTTP_403_FORBIDDEN)article.status = 'published'if not article.publish_time:article.publish_time = timezone.now()article.save()serializer = self.get_serializer(article)return Response(serializer.data)@action(detail=False, methods=['get'], permission_classes=[IsAuthenticated])def my_articles(self, request):"""获取当前用户的文章"""articles = self.get_queryset().filter(author=request.user)page = self.paginate_queryset(articles)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)serializer = self.get_serializer(articles, many=True)return Response(serializer.data)@action(detail=False, methods=['get'])def featured(self, request):"""获取推荐文章"""featured_articles = self.get_queryset().filter(is_featured=True, status='published')page = self.paginate_queryset(featured_articles)if page is not None:serializer = self.get_serializer(page, many=True)return self.get_paginated_response(serializer.data)serializer = self.get_serializer(featured_articles, many=True)return Response(serializer.data)@action(detail=True, methods=['get'])def statistics(self, request, pk=None):"""获取文章统计信息"""article = self.get_object()return Response({'id': article.id,'title': article.title,'view_count': article.view_count,'like_count': article.like_count,'created_time': article.created_time,'days_online': (timezone.now() - article.created_time).days if article.created_time else 0})

5. 路由配置详解

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')# API URL模式
urlpatterns = [path('api/', include(router.urls)),path('api-auth/', include('rest_framework.urls')),  # DRF的登录视图
]# 可选:添加自定义API文档
from rest_framework.documentation import include_docs_urls
urlpatterns += [path('api/docs/', include_docs_urls(title='Blog API Documentation')),
]

6. 分页与过滤配置

settings.py中配置全局分页和过滤:

REST_FRAMEWORK = {'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination','PAGE_SIZE': 20,'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend','rest_framework.filters.SearchFilter','rest_framework.filters.OrderingFilter',],'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework.authentication.SessionAuthentication','rest_framework.authentication.TokenAuthentication',],'DEFAULT_PERMISSION_CLASSES': ['rest_framework.permissions.IsAuthenticatedOrReadOnly',],'DEFAULT_RENDERER_CLASSES': ['rest_framework.renderers.JSONRenderer','rest_framework.renderers.BrowsableAPIRenderer',],'DEFAULT_PARSER_CLASSES': ['rest_framework.parsers.JSONParser','rest_framework.parsers.FormParser','rest_framework.parsers.MultiPartParser',],
}

7. 完整API接口测试

现在我们已经完成了完整的API开发,可以通过以下方式测试:

获取文章列表

GET /api/articles/

创建新文章

POST /api/articles/
{"title": "我的第一篇文章","content": "这是文章内容...","status": "draft"
}

获取单篇文章

GET /api/articles/1/

更新文章

PUT /api/articles/1/
{"title": "更新后的标题","content": "更新后的内容...","status": "published"
}

删除文章

DELETE /api/articles/1/

自定义动作

POST /api/articles/1/like/      # 点赞
POST /api/articles/1/publish/   # 发布文章
GET /api/articles/my_articles/  # 我的文章
GET /api/articles/featured/     # 推荐文章
GET /api/articles/1/statistics/ # 文章统计

8. 高级特性与最佳实践

8.1 信号处理

from django.db.models.signals import post_save, pre_save
from django.dispatch import receiver
from .models import Article@receiver(pre_save, sender=Article)
def update_article_slug(sender, instance, **kwargs):"""自动更新slug"""if not instance.slug:from django.utils.text import slugifyinstance.slug = slugify(instance.title)@receiver(post_save, sender=Article)
def log_article_activity(sender, instance, created, **kwargs):"""记录文章活动日志"""action = 'created' if created else 'updated'# 记录到日志系统或活动流

8.2 自定义异常处理

from rest_framework.views import exception_handler
from rest_framework.response import Responsedef custom_exception_handler(exc, context):"""自定义异常处理"""response = exception_handler(exc, context)if response is not None:response.data = {'error': {'code': response.status_code,'message': response.data.get('detail', '发生错误'),'details': response.data}}return response

8.3 性能优化

class ArticleViewSet(viewsets.ModelViewSet):def get_queryset(self):"""使用select_related和prefetch_related优化查询"""return Article.objects.select_related('author').prefetch_related('tags')

9. 总结

通过这个完整的示例,我们展示了如何使用Django REST Framework开发功能丰富的API接口。主要涵盖:

  1. 模型设计:创建具有实际业务意义的数据库模型

  2. 序列化器:实现复杂的数据验证和转换逻辑

  3. 视图集:利用DRF的ViewSet提供完整的CRUD操作

  4. 权限控制:实现细粒度的访问控制

  5. 过滤搜索:提供灵活的数据查询能力

  6. 自定义动作:扩展标准REST接口

  7. 路由配置:自动生成API端点

  8. 最佳实践:包括异常处理、性能优化等

DRF的强大之处在于其模块化设计和丰富的功能,使得开发者可以快速构建出符合生产标准的API接口。通过合理使用DRF提供的各种组件,我们可以创建出既强大又易于维护的Web API。

http://www.dtcms.com/a/458296.html

相关文章:

  • 建网站哪个公司好wordpress获取文章二级菜单
  • 德阳网站建设平台天津高端网站建设公司
  • Lookup | TryHackMe
  • Linux 端口管理完全指南:查询占用、检查开放与手动开放实操
  • 建站网站关键词优化动态的网站大概多少钱
  • 2025年--Lc178--H746. 使用最小花费爬楼梯(动态规划)--Java版
  • 济南易搜的网站建设商务网站设计论文
  • 用Slurm高效提交深度学习任务:以KBQA实体消歧任务为例
  • 完成网站建设成本设计师在线接单
  • 知名的摄影网站有哪些做班级玩网站做哪些方面
  • 推荐专业的数字化转型专家,助力企业加速数字化转型
  • 后端篇——Java SpringBoot、Node和Python Flask等
  • Java自动化测试之断言
  • 最好的微网站建设公司做暧动漫视频在线观看网站
  • 鹰潭网站建设yt1983湛江专业的建站托管
  • 做网站属于技术开发吗网站套模版
  • Serverless与Web Worker的异构计算实践
  • 就业服务工作站建设规范网站建设佰首选金手指二七
  • 网站的字体做多大合适淄博淘宝网站建设
  • html设计素材网站公司网站免费模板
  • 模板建站网络服务器搭建配置与管理 下载
  • 做装修公司网站费用综合性电商网站建设
  • iBiz开源 AI多模态辅助建模iBizAttendance(考勤管理)
  • 安徽网站优化哪里有旅游网络网站建设方案
  • 全球外贸网站有哪些lnmp wordpress 主题
  • 佛山网站制作哪家便宜住房和建设局
  • 【LeetCode】56. 合并区间
  • 深圳东莞的网站建设公司wordpress文章内翻页
  • 德州整站优化十堰seo优化哪家公司好
  • 始成年期个体的生涯探索