摘要:确认创建成功后,记得在中注册因为我们想显示发表评论的时间,修改时区设置为上海的时区。处理错误请求发表评论仅接受请求。返回到一个适当的中即用户发送评论后,重新定向到文章详情页面。总结本章实现了发表评论展示评论的功能。
在没有互联网的年代,我们用日记来记录每天的心得体会。小的时候我有一个带锁的日记本,生怕被别人看见里面写了啥,钥匙藏得那叫一个绝。
现在时代变了,网络版的日记本:博客,却巴不得越多人看越好。
别人看完你写的深度好文,难免也想高谈阔论一番,这就是“评论”功能。
本章将要编写的评论模块,几乎没有新的知识点,而是将前面章节内容的综合应用。
强烈建议读者自行尝试编写这部分内容,测试自己的知识掌握程度。
准备工作评论是一个相对独立的功能,因此新建一个评论的app:
(env) E:django_projectmy_blog > ppython manage.py startapp comment
有的人觉得奇怪,没有博文就没有评论,为什么说评论是“独立”的功能?那是因为不仅博文可以评论,照片、视频甚至网站本身都可以“被评论”。将其封装成多带带的模块方便以后的扩展。
确认app创建成功后,记得在settings.py中注册:
my_blog/settings.py
...
INSTALLED_APPS = [
...
"comment",
]
...
TIME_ZONE = "Asia/Shanghai"
...
因为我们想显示发表评论的时间,修改时区设置TIME_ZONE为上海的时区。
然后在my_blog/urls.py中注册根路由:
my_blog/urls.py
...
urlpatterns = [
...
# 评论
path("comment/", include("comment.urls", namespace="comment")),
]
...
编写核心功能
评论的模型
首先编写评论的模型:
comment/models.py
from django.db import models
from django.contrib.auth.models import User
from article.models import ArticlePost
# 博文的评论
class Comment(models.Model):
article = models.ForeignKey(
ArticlePost,
on_delete=models.CASCADE,
related_name="comments"
)
user = models.ForeignKey(
User,
on_delete=models.CASCADE,
related_name="comments"
)
body = models.TextField()
created = models.DateTimeField(auto_now_add=True)
class Meta:
ordering = ("created",)
def __str__(self):
return self.body[:20]
模型中共有2个外键:
article是被评论的文章
user是评论的发布者
别忘了每次新增、修改Model后,必须数据迁移。
提示:你必须先在setting.py中注册app,这个app中的数据迁移才能生效评论的表单
用户提交评论时会用到表单,因此新建表单类:
comment/forms.py
from django import forms
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ["body"]
因为模型中的2个外键将通过视图逻辑自动填写,所以这里只需要提交body就足够了。
评论的url在comment app中新建路由文件:
comment/urls.py
from django.urls import path
from . import views
app_name = "comment"
urlpatterns = [
# 发表评论
path("post-comment//", views.post_comment, name="post_comment"),
]
评论必须关联在某篇具体的博文里,因此传入博文的id,方便后续调用。
post_comment()视图还没写,先取个名字占位置。
评论的视图评论的视图函数如下:
comment/views.py
from django.shortcuts import render, get_object_or_404, redirect
from django.contrib.auth.decorators import login_required
from django.http import HttpResponse
from article.models import ArticlePost
from .forms import CommentForm
# 文章评论
@login_required(login_url="/userprofile/login/")
def post_comment(request, article_id):
article = get_object_or_404(ArticlePost, id=article_id)
# 处理 POST 请求
if request.method == "POST":
comment_form = CommentForm(request.POST)
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.article = article
new_comment.user = request.user
new_comment.save()
return redirect(article)
else:
return HttpResponse("表单内容有误,请重新填写。")
# 处理错误请求
else:
return HttpResponse("发表评论仅接受POST请求。")
代码中有2个新面孔。
get_object_or_404():它和Model.objects.get()的功能基本是相同的。区别是在生产环境下,如果用户请求一个不存在的对象时,Model.objects.get()会返回Error 500(服务器内部错误),而get_object_or_404()会返回Error 404。相比之下,返回404错误更加的准确。
redirect():返回到一个适当的url中:即用户发送评论后,重新定向到文章详情页面。当其参数是一个Model对象时,会自动调用这个Model对象的get_absolute_url()方法。因此接下来马上修改article的模型。
实际上之前的章节已经用过redirect()了。功能是相同的,实现上略有区别。文章的模型
按照上面说的,在文章模型中添加get_absolute_url()方法:
article/models.py
...
# 记得导入
from django.urls import reverse
class ArticlePost(models.Model):
...
# 获取文章地址
def get_absolute_url(self):
return reverse("article:article_detail", args=[self.id])
通过reverse()方法返回文章详情页面的url,实现了路由重定向。
文章详情视图评论模块需要在文章详情页面展示,所以必须把评论模块的上下文也传递到模板中。
因此修改article/views.py中的article_detail():
article/views.py
...
from comment.models import Comment
def article_detail(request, id):
# 已有代码
article = ArticlePost.objects.get(id=id)
# 取出文章评论
comments = Comment.objects.filter(article=id)
...
# 添加comments上下文
context = { "article": article, "toc": md.toc, "comments": comments }
...
filter()可以取出多个满足条件的对象,而get()只能取出1个,注意区分使用文章详情模板
到最后一步了,坚持。所有后台的功能已经写完了,就差把所有这些展现到页面中了。
修改文章详情页面:
templates/article/detail.html .........
{% if user.is_authenticated %}
{% else %}
请登录后回复
{% endif %}共有{{ comments.count }}条评论
{% for comment in comments %}
{{ comment.user }} 于 {{ comment.created|date:"Y-m-d H:i:s" }} 时说:
{{ comment.body }}{% endfor %}......
表单组件中的action指定数据提交到哪个url中
显示评论中的comments.count是模板对象中内置的方法,对包含的元素进行计数
|date:"Y-m-d H:i:s":管道符你已经很熟悉了,用于给对象“粘贴”某些属性或功能。这里用于格式化日期的显示方式。请尝试修改其中的某些字符试试效果。
定义预格式化的文本,在我们的项目中最关键的作用是保留空格和换行符。该标签会改变文字的字体、大小等,因此用style属性重新定义相关内容。尝试将替换为div,输入多行文本试试效果。
之前说代码最好不要复制粘贴,否则有些“小坑”你是留意不到的。比如在标签中的文本千万不能缩进。测试
又到了激动人心的测试环节了。
登录自己的账户,进入某个文章详情页面,发现已经可以进行留言了:
如果退出登录,显示提示语:
点击登录就回到登录页面。
评论模块的发布、展示功能就搞定了。
扫尾工作数据的删、改功能我们已经做过很多遍,这里不打算再赘述了。
评论同样也可以支持Markdown语法,或者插入Emoji表情符号。
读者可以自己去实现感兴趣的功能。
有些网站干脆就没有删除、更新评论的功能。因为对小站来说,这些功能用到的次数太少太少了,不如把精力用在更有价值的地方去。比如我的博客就没有。总结还有的网站提供软删除,删除后仅仅是不显示而已,实际上数据还存在。
具体应该如何做,都以你的喜好而定。
本章实现了发表评论、展示评论的功能。像开头说的一样,本章的内容是前面所学章节的综合。
如果你没有看本章代码,而是完全靠自己完成了评论功能,那么恭喜你获得了“Django入门程序员”的称号!不要小看“入门”两字,万事开头难嘛。
有疑问请在杜赛的个人网站留言,我会尽快回复。
或Email私信我:dusaiphoto@foxmail.com
项目完整代码:Django_blog_tutorial
转载请注明出处。
文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。
转载请注明本文地址:https://www.ucloud.cn/yun/42908.html
摘要:在父页面中文章详情模板添加需要执行锚点拼接的函数新增函数,处理二级回复去除尾部符号刷新并定位到锚点函数中运用了的三元运算符,翻译成人话就是如果成立则返回,如果不成立就返回。 老读者注意:上一章消息通知有个bug,即发给管理员的notify必须移动到new_comment.save()的后面,否则会导致action_object存储为NULL,并且导致本章的html拼接锚点失效。原文已...
摘要:接下来你就可以在项目的任何地方发送通知了像这样其中的参数释义发送通知的对象接收通知的对象动词短语链接到动作的对象可选执行通知的对象可选有点绕,举个栗子杜赛在搭建个人博客中对你发表了评论。有疑问请在杜赛的个人网站留言,我会尽快回复。 凭借你勤奋的写作,拜读你文章的用户越来越多,他们的评论也分散在众多的文章之中。作为博主,读者的留言肯定是要都看的;而读者给你留言,自然也希望得到回复。 怎么...
摘要:后面两个编辑器自带,不用单独下载,添上就可以了添加相关插件这样就完成了代码高亮效果不错在前台使用为了让用户在前台也能使用富文本编辑器,还得对代码稍加改动。对于有些不喜欢的人来说,甚至可以连博文都使用提供的富文本编辑器。 前面我们已经实现了用Markdown语法写文章了。但是文章的评论用Markdown就不太合适了,你不能强求用户也花时间去熟悉语法啊。另外评论中通常还有表情、带颜色的字体...
摘要:教程看到这里,你已经学会如下内容搭建开发环境博文管理用户管理发表评论若干小功能搭建简单的小博客,以上的功能够用了。教程为了起步平缓,没有展开这方面的内容。陌生人,祝你学业进步事业有成欢迎常到杜赛的个人网站做客 教程看到这里,你已经学会如下内容: 搭建开发环境 博文管理 用户管理 发表评论 若干小功能 搭建简单的小博客,以上的功能够用了。 相信你的志向不止于此。毕竟程序员面试个个造火...
摘要:语法支持再次打开文件,在文件的最后添加指明了使用语法标记,做了两个拓展,其中表示支持语法高亮,包含的特性请参见相关文档。语法高亮支持注意这一步必须在安装完主题之后。 目前网上搭建个人博客的方案很多,虽然使用诸如 Wordpress ( PHP )、Hexo ( Node.js ) 等可以方便快速地搭建一款功能齐全的高性能个人博客,但是本文将尝试一种更为小众化的方案 —— 一款基于 dj...
阅读 1195·2021-09-03 10:42
阅读 1739·2019-08-30 15:56
阅读 1747·2019-08-29 17:27
阅读 1103·2019-08-29 15:25
阅读 3535·2019-08-26 18:27
阅读 2724·2019-08-26 13:41
阅读 2134·2019-08-26 10:39
阅读 1957·2019-08-23 18:36