这里编辑模型使用navicat自带的编辑工具:
这个工具也算是我尝试过用起来最为舒服的数据库模型设计工具了。
模型暂时设计成这样,后面再有其他的需求再添加字段:
tb_article是文章表,其中的title,abstract和content分别对应标题、摘要和内容,tb_tag_of_article是文章的标签,一个文章可以有多个标签,一个标签也可以对应多篇文章,故它们之间是多对多的关系,所以需要一张中间表将它们联系起来(这只是在建模时候需要,将模型映射到Django ORM时可以直接使用多对多关系不用显示创建中间表)
因为基本所有的记录都需要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
方式 | url | 功能 |
---|---|---|
get | /blog/article_tags/ | 提供所有标签记录 |
post | /blog/article_tags/ | 新增一个标签 |
get | /blog/article_tags/ |
提供指定id的标签 |
put | /blog/article_tags/ |
修改指定id的标签 |
delete | /blog/article_tags/ |
删除指定id的标签 |
接受的json数据
{
"tag_name": 标签名
}
方式 | url | 功能 |
---|---|---|
get | /blog/articles/ | 提供所有文章记录 |
post | /blog/articles/ | 新增一篇文章 |
get | /blog/articles/ |
提供指定id的文章 |
put | /blog/articles/ |
修改指定id的文章 |
delete | /blog/articles/ |
删除指定id的文章 |
post | /blog/articles/ |
* 为指定文章添加列表中的标签 |
delete | /blog/articles/ |
* 为指定文章删除列表中的标签 |
接受的json数据
一般:
{
"article_title": 文章标题,
"article_abstract": 文章摘要,
"article_content": 文章内容
},
为文章添加和修改标签:
{
"tag_ids": [标签id, "标签名", ...]
}
通过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__'
这里标签的序列化器我分成了两种
# 列表序列化器
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++基础内容"
}
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
# /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'))
]