文章目录
一、任务
- 设计博客文章的数据库模型(ER关系图)
- 将数据库模型映射到Django模型类
- 使用DRF完成基本的增删改查
二、设计博客文章的数据库模型(ER关系图)
这里编辑模型使用navicat自带的编辑工具:

这个工具也算是我尝试过用起来最为舒服的数据库模型设计工具了。
模型暂时设计成这样,后面再有其他的需求再添加字段:

tb_article是文章表,其中的title,abstract和content分别对应标题、摘要和内容,tb_tag_of_article是文章的标签,一个文章可以有多个标签,一个标签也可以对应多篇文章,故它们之间是多对多的关系,所以需要一张中间表将它们联系起来(这只是在建模时候需要,将模型映射到Django ORM时可以直接使用多对多关系不用显示创建中间表)
三、将数据库模型映射到Django模型类
编写模型类的虚拟基类
因为基本所有的记录都需要createTime和updateTime这两个字段(如文章记录需要文章创建时间,更改时间等等),所以我们在虚拟基类BaseModel中写入这两个字段,其他的模型类继承BaseModel即可。
代码编写:
先创建一个模块(app),命名为blog,专门负责处理关于博客信息的请求和存储。
> manage.py startapp blog
添加到settings中
然后在项目配置文件夹中添加一个utils包,并新建models.py文件:

写入:
from django.db import models
class BaseModel(models.Model):
create_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
update_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
class Meta:
abstract = True #这句代码表示抽象继承
编写文章和标签模型
# /blog/models.py
class Article(BaseModel):
article_title = models.CharField(max_length=255, verbose_name="文章标题")
article_abstract = models.CharField(max_length=255, verbose_name="文章摘要")
article_content = models.TextField(verbose_name="文章内容")
article_tags = models.ManyToManyField('TagOfArticle', verbose_name='文章标签', related_name='tag_articles')
def __str__(self):
return self.article_title
class Meta:
db_table = 'tb_article'
verbose_name = '文章'
verbose_name_plural = verbose_name
class TagOfArticle(BaseModel):
tag_name = models.CharField(max_length=255, verbose_name="文章标签")
def __str__(self):
return self.tag_name
def related_article_num(self):
return Article.objects.filter(article_tags=self).count()
class Meta:
db_table = 'tb_tag_of_article'
verbose_name = '文章标签'
verbose_name_plural = verbose_name
进行迁移
> manage.py makemigrations
> manage.py migrate
可以看到数据库中产生了我们需要的表:

四、使用DRF完成基本的增删改查
1.接口定义
标签接口
| 方式 | url | 功能 |
|---|---|---|
| get | /blog/article_tags/ | 提供所有标签记录 |
| post | /blog/article_tags/ | 新增一个标签 |
| get | /blog/article_tags/<pk>/ | 提供指定id的标签 |
| put | /blog/article_tags/<pk>/ | 修改指定id的标签 |
| delete | /blog/article_tags/<pk>/ | 删除指定id的标签 |
接受的json数据
{
"tag_name": 标签名
}
文章接口
| 方式 | url | 功能 |
|---|---|---|
| get | /blog/articles/ | 提供所有文章记录 |
| post | /blog/articles/ | 新增一篇文章 |
| get | /blog/articles/<pk>/ | 提供指定id的文章 |
| put | /blog/articles/<pk>/ | 修改指定id的文章 |
| delete | /blog/articles/<pk>/ | 删除指定id的文章 |
| post | /blog/articles/<pk>/article_op_tag/ | * 为指定文章添加列表中的标签 |
| delete | /blog/articles/<pk>/article_op_tag/ | * 为指定文章删除列表中的标签 |
接受的json数据
一般:
{
"article_title": 文章标题,
"article_abstract": 文章摘要,
"article_content": 文章内容
},
为文章添加和修改标签:
{
"tag_ids": [标签id, "标签名", ...]
}
2.编写序列化器
文章序列化器
通过TagSimpleSerializer来获取一篇文章对应的多个标签
# 为文章序列化器服务的标签序列化器
class TagSimpleSerializer(serializers.ModelSerializer):
class Meta:
model = TagOfArticle
fields = ['id', 'tag_name']
# 文章序列化器
class ArticleSerializer(serializers.ModelSerializer):
# 携带文章的标签
article_tags = TagSimpleSerializer(many=True, read_only=True)
class Meta:
model = Article
fields = '__all__'
标签序列化器
这里标签的序列化器我分成了两种
- 一种是请求列表视图时使用的序列化器,里面包含一个新字段related_article_num,表示标着这个标签的文章数目
- 另一种是详情序列化器,里面包含新字段tag_articles,即这个标签所对应的全部文章都使用ArticleSerializer进行序列化后返回文章的所有信息。
# 列表序列化器
class TagOfArticleListSerializer(serializers.ModelSerializer):
# 获得当前标签的文章数目,只读字段
related_article_num = serializers.CharField(read_only=True)
class Meta:
model = TagOfArticle
fields = '__all__'
# 详情序列化器
class TagOfArticleDetailSerializer(serializers.ModelSerializer):
tag_articles = ArticleSerializer(many=True, read_only=True)
class Meta:
model = TagOfArticle
fields = '__all__'
即效果为:
- 列表视图:
[
{
"id": 1,
"related_article_num": 1, <--除了获取标签的基本信息外,还可以获取该标签对应的文章数目
"create_time": "2021-04-20T14:42:47.295950Z",
"update_time": "2021-04-20T14:42:47.295950Z",
"tag_name": "c++基础内容"
},
{
"id": 2,
"related_article_num": 1,
...
"tag_name": "设计模式"
}
]
- 详情视图:
{
"id": 1,
"tag_articles": [ #在这里还返回了对应文章信息的列表
{
"id": 1,
"article_tags": [
"c++基础内容",
"设计模式"
],
...
"article_title": "第一篇文章",
"article_abstract": "第一篇文章",
"article_content": "第一篇文章的内容"
}
],
...
"tag_name": "c++基础内容"
}
3.编写视图
文章视图
class ArticleViewSet(ModelViewSet):
queryset = Article.objects.all()
serializer_class = ArticleSerializer
@action(methods=['POST', 'DELETE'], detail=True)
def article_op_tag(self, request, pk):
article = self.get_object()
data = request.data
"""
{tag_id: 2}
"""
tag_ids = data['tag_ids']
for tag_id in tag_ids:
if request.method == 'POST' and isinstance(tag_id, str):
new_tag = TagOfArticle.objects.create(tag_name=tag_id)
tag_id = new_tag.id
tag = get_object_or_404(TagOfArticle, pk=tag_id)
if request.method == 'POST':
article.article_tags.add(tag)
else:
article.article_tags.remove(tag)
serializer = ArticleSerializer(instance=article)
return Response(serializer.data)
标签视图
这里对请求的视图做了区分,如果为请求列表视图,则使用ListSerializer,而请求详情视图时使用DetailSerializer
class TagOfArticleViewSet(ModelViewSet):
def get_queryset(self):
return TagOfArticle.objects.all()
def get_serializer_class(self):
if self.action == 'list':
return TagOfArticleListSerializer
else:
return TagOfArticleDetailSerializer
4.配置路由
# /blog/urls.py
from . import views
from rest_framework.routers import SimpleRouter
urlpatterns = [
]
router = SimpleRouter()
router.register(r'article_tags', views.TagOfArticleViewSet, basename='article_tags')
router.register(r'articles', views.ArticleViewSet, basename='articles')
urlpatterns += router.urls
主路由:
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('blog/', include('blog.urls'))
]
5.测试
-
文章列表

-
文章详情

-
标签列表

-
标签详情

上一步:Vue+DRF搭建博客之后端篇(一)
下一步:Vue+DRF搭建博客之前端篇(四)

本文介绍如何使用Django REST framework(DRF)实现博客系统的增删改查功能,涵盖数据库模型设计、模型映射到Django ORM、序列化器编写、视图及路由设置等关键步骤。
2354

被折叠的 条评论
为什么被折叠?



