基于 Django 5 + DRF 构建博客系统后端接口(从建模到接口实现)

作者:张大鹏

更新时间:2025年10月

适用版本:Python 3.12 / Django 5.x / Django REST Framework 3.15+


一、前言

在现代 Web 开发中,前后端分离已成为主流架构。对于一个博客系统来说,后端的职责不仅仅是提供数据存储,还需要负责用户认证、权限控制、数据序列化、分页过滤、接口安全等。

本文将详细介绍如何使用 Django 5 + Django REST Framework (DRF) 构建一个高质量的博客系统后端接口,涵盖从建模、序列化到接口开发的完整流程。


二、项目结构设计

我们采用模块化结构组织项目,目录如下:

复制代码
blog_project/
│
├── blog_api/                 # Django 应用(主要业务逻辑)
│   ├── models.py             # 模型层
│   ├── serializers.py        # 序列化器
│   ├── views.py              # 视图(API 接口)
│   ├── urls.py               # 路由配置
│   └── permissions.py        # 自定义权限
│
├── blog_project/
│   ├── settings.py           # 项目配置
│   ├── urls.py               # 全局路由
│   └── wsgi.py
│
└── manage.py

三、环境准备

bash 复制代码
# 创建虚拟环境
python -m venv venv
source venv/bin/activate  # Windows: venv\Scripts\activate

# 安装依赖
pip install django==5.0.4 djangorestframework==3.15.0 djangorestframework-simplejwt

创建项目与应用:

bash 复制代码
django-admin startproject blog_project
cd blog_project
python manage.py startapp blog_api

settings.py 中注册应用与 DRF:

python 复制代码
INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'rest_framework',
    'blog_api',
]

配置 DRF:

python 复制代码
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': 10
}

四、模型设计(Models)

我们复用上一篇 MySQL 设计的核心结构,在 Django ORM 中实现:

python 复制代码
# blog_api/models.py

from django.db import models
from django.contrib.auth.models import User

class Category(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(unique=True)
    description = models.CharField(max_length=255, blank=True, null=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name


class Tag(models.Model):
    name = models.CharField(max_length=50, unique=True)
    slug = models.SlugField(unique=True)
    created_at = models.DateTimeField(auto_now_add=True)

    def __str__(self):
        return self.name


class Post(models.Model):
    STATUS_CHOICES = (
        (0, 'Draft'),
        (1, 'Published'),
    )
    author = models.ForeignKey(User, on_delete=models.CASCADE, related_name='posts')
    category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
    title = models.CharField(max_length=200)
    content = models.TextField()
    summary = models.CharField(max_length=500, blank=True)
    cover_image = models.URLField(blank=True, null=True)
    status = models.IntegerField(choices=STATUS_CHOICES, default=1)
    view_count = models.PositiveIntegerField(default=0)
    tags = models.ManyToManyField(Tag, blank=True, related_name='posts')
    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    class Meta:
        ordering = ['-created_at']

    def __str__(self):
        return self.title


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.CASCADE, related_name='comments')
    user = models.ForeignKey(User, on_delete=models.CASCADE)
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True, blank=True)
    content = models.TextField()
    created_at = models.DateTimeField(auto_now_add=True)

    class Meta:
        ordering = ['created_at']

    def __str__(self):
        return f'{self.user.username} - {self.content[:20]}'

五、序列化层(Serializers)

DRF 的序列化器将模型与 JSON 格式数据之间的转换自动化。

python 复制代码
# blog_api/serializers.py

from rest_framework import serializers
from .models import Post, Category, Tag, Comment

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


class CategorySerializer(serializers.ModelSerializer):
    class Meta:
        model = Category
        fields = ['id', 'name', 'slug', 'description']


class CommentSerializer(serializers.ModelSerializer):
    user = serializers.StringRelatedField(read_only=True)

    class Meta:
        model = Comment
        fields = ['id', 'user', 'content', 'parent', 'created_at']


class PostSerializer(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)

    class Meta:
        model = Post
        fields = [
            'id', 'title', 'summary', 'content',
            'author', 'category', 'tags', 'comments',
            'view_count', 'status', 'created_at'
        ]

六、视图层(Views)

我们使用 DRF 的 ModelViewSet 来快速生成标准的 CRUD 接口。

python 复制代码
# blog_api/views.py

from rest_framework import viewsets, permissions
from .models import Post, Category, Tag, Comment
from .serializers import PostSerializer, CategorySerializer, TagSerializer, CommentSerializer

class CategoryViewSet(viewsets.ModelViewSet):
    queryset = Category.objects.all()
    serializer_class = CategorySerializer
    permission_classes = [permissions.IsAdminUser]


class TagViewSet(viewsets.ModelViewSet):
    queryset = Tag.objects.all()
    serializer_class = TagSerializer
    permission_classes = [permissions.IsAdminUser]


class PostViewSet(viewsets.ModelViewSet):
    queryset = Post.objects.filter(status=1)
    serializer_class = PostSerializer

    def perform_create(self, serializer):
        serializer.save(author=self.request.user)


class CommentViewSet(viewsets.ModelViewSet):
    queryset = Comment.objects.all()
    serializer_class = CommentSerializer

    def perform_create(self, serializer):
        serializer.save(user=self.request.user)

七、路由与接口配置

blog_api/urls.py 中:

python 复制代码
from rest_framework.routers import DefaultRouter
from .views import PostViewSet, CategoryViewSet, TagViewSet, CommentViewSet

router = DefaultRouter()
router.register(r'posts', PostViewSet)
router.register(r'categories', CategoryViewSet)
router.register(r'tags', TagViewSet)
router.register(r'comments', CommentViewSet)

urlpatterns = router.urls

然后在项目 urls.py 中引入:

python 复制代码
# blog_project/urls.py
from django.contrib import admin
from django.urls import path, include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('api/', include('blog_api.urls')),
]

现在,启动项目:

bash 复制代码
python manage.py makemigrations
python manage.py migrate
python manage.py runserver

访问接口:

  • GET /api/posts/ → 获取文章列表
  • POST /api/posts/ → 发布文章(需登录)
  • GET /api/comments/?post=1 → 获取文章评论
  • POST /api/comments/ → 发表评论

八、JWT 用户认证

使用 djangorestframework-simplejwt 实现 Token 登录认证:

python 复制代码
# blog_project/urls.py

from rest_framework_simplejwt.views import (
    TokenObtainPairView, TokenRefreshView
)

urlpatterns += [
    path('api/token/', TokenObtainPairView.as_view(), name='token_obtain_pair'),
    path('api/token/refresh/', TokenRefreshView.as_view(), name='token_refresh'),
]

现在可以通过:

  • POST /api/token/ 获取 JWT;
  • Authorization: Bearer <token> 访问受保护接口。

九、性能与安全优化建议

  1. 分页与过滤

    • 使用 django-filter 实现文章按分类、标签过滤;
    • 开启 DRF 内置分页。
  2. 缓存与统计

    • 使用 Redis 缓存热门文章;
    • 使用信号量(post_save)记录浏览数。
  3. 权限管理

    • 自定义权限类,例如"作者本人才能修改自己的文章"。
  4. 跨域访问(CORS)

    bash 复制代码
    pip install django-cors-headers
    python 复制代码
    INSTALLED_APPS += ['corsheaders']
    MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware')
    CORS_ALLOW_ALL_ORIGINS = True

十、总结

通过本文,我们完成了从 Django ORM 建模 → DRF 序列化 → ViewSet 路由 → JWT 认证 的完整开发流程。

至此,你已具备开发一个可运行的 博客后端 API 的能力,后续可以继续扩展:

  • ✅ 点赞与收藏接口
  • ✅ 文章全文搜索(结合 Elasticsearch)
  • ✅ 富文本编辑与 Markdown 支持
  • ✅ 日志与监控集成
相关推荐
南方的狮子先生5 小时前
【深度学习】60 分钟 PyTorch 极速入门:从 Tensor 到 CIFAR-10 分类
人工智能·pytorch·python·深度学习·算法·分类·1024程序员节
闲人编程5 小时前
Docker化你的Python应用:从开发到生产
python·docker·eureka·开发·生产·codecapsule
JJJJ_iii5 小时前
【机器学习10】项目生命周期、偏斜类别评估、决策树
人工智能·python·深度学习·算法·决策树·机器学习
IT北辰6 小时前
用 Python 实现连续数据分组求和并回写
开发语言·python
小白学大数据6 小时前
从携程爬取的杭州酒店数据中提取价格、评分与评论的关键信息
爬虫·python·性能优化
IT学长编程7 小时前
计算机毕业设计 基于Python的热门游戏推荐系统的设计与实现 Django 大数据毕业设计 Hadoop毕业设计选题【附源码+文档报告+安装调试】
大数据·python·django·毕业设计·课程设计·毕业论文
Ashlee_code8 小时前
什么是TRS收益互换与场外个股期权:从金融逻辑到系统开发实践
大数据·人工智能·python·金融·系统架构·清算·柜台
今天没有盐8 小时前
Python编程实战:日期处理与数学算法综合练习
python·pycharm·编程语言
pop_xiaoli8 小时前
SQLite3语句以及FMDB数据存储初步学习
学习·ios·sqlite·objective-c·cocoa