作者:张大鹏
更新时间: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>访问受保护接口。
九、性能与安全优化建议
-
分页与过滤
- 使用
django-filter实现文章按分类、标签过滤; - 开启 DRF 内置分页。
- 使用
-
缓存与统计
- 使用 Redis 缓存热门文章;
- 使用信号量(
post_save)记录浏览数。
-
权限管理
- 自定义权限类,例如"作者本人才能修改自己的文章"。
-
跨域访问(CORS)
bashpip install django-cors-headerspythonINSTALLED_APPS += ['corsheaders'] MIDDLEWARE.insert(0, 'corsheaders.middleware.CorsMiddleware') CORS_ALLOW_ALL_ORIGINS = True
十、总结
通过本文,我们完成了从 Django ORM 建模 → DRF 序列化 → ViewSet 路由 → JWT 认证 的完整开发流程。
至此,你已具备开发一个可运行的 博客后端 API 的能力,后续可以继续扩展:
- ✅ 点赞与收藏接口
- ✅ 文章全文搜索(结合 Elasticsearch)
- ✅ 富文本编辑与 Markdown 支持
- ✅ 日志与监控集成