教程来源 杜塞-django-vue系列
博客链接 传送门
上一章我们做好了评论功能,就有了作者和读者沟通的方式。
但是有的时候读者和读者也需要沟通,评论别人的评论,俗称多级评论。
本章就将实现基础的多级评论功能。
精确的讲是二级评论。
模型
多级评论,也就是让评论模型和自身相关联。使其可以有一个父级。
修改评论模型,新增parent
字段:
# comment/models.py
class Comment(models.Model):
···
parent = models.ForeignKey(
'self',
null=True,
blank=True,
on_delete=models.SET_NULL,
related_name='children'
)
- 一个父评论可以拥有多个自评论,而子评论只能有一个父评论,因此用了一个一对多外键。
- 之前的一对多外键,第一个参数直接引用对应模型,但是由于python语法限制,这里显然不能引用自己,因此用了
传递字符串的self方法,作用是一样的。
需要数据迁移!!!
序列化器
在原有序列化器上进行修改:
# comment/serializers.py
# 新增类
class CommentChildrenSerializer(serializers.ModelSerializer):
url = serializers.HyperlinkedIdentityField(view_name='comment-detail')
author = UserDescSerializer(read_only=True)
class Meta:
model = Comment
exclude = [
'parent',
'article'
]
class CommentSerializer(serializers.ModelSerializer):
url = ···
author = ···
# 新增代码
article = serializers.HyperlinkedRelatedField(view_name='article-detail',read_only=True)
article_id = serializers.IntegerField(write_only=True,allow_null=False,required=True)
parent = CommentChildrenSerializer(read_only=True)
parent_id = serializers.IntegerField(write_only=True,allow_null=True,required=True)
def update(self, instance, validated_data):
validated_data.pop('parent_id',None)
return super().update(instance,validated_data)
新增代码大致可以分三块,让我们拆解:
- 为了让文章更人性化,我们将
article
改为超链接字段用的HyperlinkedRelatedField
,他和之前的HyperlinkedIdentityField
差别很小,我们可以把HyperlinkedIdentityField
理解为用于外键关系,而HyperlinkedRelatedField
用于本身。(完整的解释看这里) parent
为父评论,用了嵌套序列化器CommentChildrenSerializer
。注意这个学历恶化其的Meta
用的是exclude
来定义不需要的字段。- 由于我们希望父评论只能在创建时被关联,后续不能更改(很合理),因此覆写
def update(...)
,使得在更新评论时忽略掉parent_id
参数。
这就完成了。接下来测试。
测试
新建一个文章主键为17,评论主键为1的一级评论:
>http -a Obama:admin123456 POST http://127.0.0.1:8000/api/comment/ article_id=17 content=one
HTTP/1.1 201 Created
···
{
"article": "http://127.0.0.1:8000/api/article/17/",
"author": {
"date_joined": "2021-06-13T06:47:00",
"id": 2,
"last_login": null,
"username": "Obama"
},
"content": "one",
"created": "2021-06-21T19:36:30.437816",
"id": 1,
"parent": null,
"url": "http://127.0.0.1:8000/api/comment/1/"
}
在此基础上创建文章主键为17,父评论为1的评论:
>http -a Obama:admin123456 POST http://127.0.0.1:8000/api/comment/ parent_id=1 article_id=17 content="comment to parent comment 17"
HTTP/1.1 201 Created
···
{
"article": "http://127.0.0.1:8000/api/article/17/",
"author": {
"date_joined": "2021-06-13T06:47:00",
"id": 2,
"last_login": null,
"username": "Obama"
},
"content": "comment to parent comment 17",
"created": "2021-06-21T19:44:27.768074",
"id": 3,
"parent": {
"author": {
"date_joined": "2021-06-13T06:47:00",
"id": 2,
"last_login": null,
"username": "Obama"
},
"content": "one",
"created": "2021-06-21T19:36:30.437816",
"id": 1,
"url": "http://127.0.0.1:8000/api/comment/1/"
},
"url": "http://127.0.0.1:8000/api/comment/3/"
}
article
改为了嵌套序列化器(只读),因此我们要用article_id
进行赋值。
如果我们想在更新评论内容的时候修改父评论:
>http -a Obama:admin123456 put http://127.0.0.1:8000/api/comment/3/ parent_id=99 article_id=17 content="update"
HTTP/1.1 200 OK
···
{
···
"content": "update",
"created": "2021-06-21T19:44:27.768074",
"id": 3,
"parent": {
···
"id": 1,
"url": "http://127.0.0.1:8000/api/comment/1/"
},
"url": "http://127.0.0.1:8000/api/comment/3/"
}
content
修改成功而parent_id
无变化。符合预期功能。
其他请求大家自行测试,这里的多级评论和一级评论会让人们分不出来,等前端开发就可以了,可以持续跟进学习。