Django之博客系统:增加评论
3既然是博客,那肯定就有留言评论系统.在这一章就来建立一个评论系统.
1 创建一个模型来保存评论
2 创建一个表单来提交评论并且验证输入的数据
3 添加一个视图函数来处理表单和保存新的评论到数据库
4 编辑帖子模板来展示评论列表以及用来添加新评论的表单
首先来创建一个模型来存储评论
class Comment(models.Model):
post=models.ForeignKey(Post,related_name='comments')
name=models.CharField(max_length=80)
email=models.EmailField()
body=models.TextField()
created=models.DateTimeField(auto_now_add=True)
updated=models.DateTimeField(auto_now=True)
active=models.BooleanField(default=True)
class Meta:
ordering = ('created',)
def __str__(self):
return 'Comments by {} on {}'.format(self.name,self.post)
这就是我们增加评论的模型,其中最关键的是post,通过ForeignKey将Comment和Post关联了起来,关联关系是多对一,原因是一个博客是有多个评论的.定义好之后,我们就可以通过commens.post来取得对应的帖子.以及通过postcomments.all()来取回一个帖子所有的评论.如果你没有定义related_name属性,Django会使用这个模型(model)的名称加上*_set*(在这里是:comment_set)来命名从相关联的对象反向定位到这个对象的manager。
接下来完成数据迁移
zhf@zhf-maple:~/py_prj/mysite$ python manage.py makemigrations blog
Migrations for 'blog':
blog/migrations/0002_auto_20180303_1216.py
- Create model Comment
- Alter field author on post
- Alter field body on post
- Alter field created on post
- Alter field publish on post
- Alter field status on post
- Alter field title on post
- Alter field updated on post
- Add field post to comment
zhf@zhf-maple:~/py_prj/mysite$ python manage.py migrate
Operations to perform:
Apply all migrations: admin, auth, blog, contenttypes, sessions
Running migrations:
Applying blog.0002_auto_20180303_1216... OK
同步增加一个评论的管理并在后台进行注册admin.site.register(Comment,CommentAdmin)
class CommentAdmin(admin.ModelAdmin):
list_display = ('name','email','post','created','active')
list_filter = ('active','created','updated')
search_fields = ('name','email','body')
创建表单:
在这里的表单和前面的邮件分享不太一样,这里通过模型来创建表单
from .models import Comment
class CommentsForm(forms.ModelForm):
class Meta:
model=Comment
fields=('name','email','body')
根据模型(model)创建表单,我们只需要在这个表单的Meta类里表明使用哪个模型(model)来构建表单。Django将会解析model并为我们动态的创建表单。每一种模型(model)字段类型都有对应的默认表单字段类型。表单验证时会考虑到我们定义模型(model)字段的方式。Django为模型(model)中包含的每个字段都创建了表单字段。然而,使用fields 列表你可以明确的告诉框架你想在你的表单中包含哪些字段,或者使用exclude 列表定义你想排除在外的那些字段。对于我们的CommentForm来说,我们在表单中只需要name,email,和body字段,因为我们只需要用到这3个字段让我们的用户来填写。
视图中操作ModelForm
根据模型
def post_list_page(request):
object_list = Post.objects.all()
paginator = Paginator(object_list, 1) # 3 posts in each page
page = request.GET.get('page')
new_comment = None
try:
posts = paginator.page(page)
comments=posts.object_list[0].comments.filter()
except PageNotAnInteger:
posts = paginator.page(1)
comments = posts.object_list[0].comments.filter()
except EmptyPage:
posts = paginator.page(paginator.num_pages)
id = posts.object_list[0].id
post = get_object_or_404(Post, id=id, status='published')
if request.method == 'POST':
comment_form = CommentsForm()
if comment_form.is_valid():
new_comment = comment_form.save(commit=False)
new_comment.post = post
new_comment.save()
else:
comment_form = CommentsForm()
return render(request,
'post/list.html',
{'page': page,
'posts': posts,
'comments':comments,
'new_comment': new_comment,
'comment_form': comment_form,
})
1 通过comments=posts.object_list[0].comments.filter()得到每个博客对应的评论实例
2 id = posts.object_list[0].id得到每个博客实例的id,并通过id得到Post实例
3 通过上传的CommentsForm表单数据将评论和博客连接起来
(1)我们通过调用这个表单的save()方法创建一个新的Comment对象
new_comment = comment_form.save(commit=False)
Save()方法创建了一个表单链接的model的实例,并将它保存到数据库中。如果你调用这个方法时设置commit=False,你创建的模型(model)实例不会即时保存到数据库中。当你想在最终保存之前修改这个model对象会非常方便,我们接下来将做这一步骤。save()方法是给ModelForm用的,而不是给Form实例用的,因为Form实例没有关联上任何模型(model)
为刚才的评论分配一个帖子
new_comment.post = post
(3) 最后,我们用下面的代码将新的评论保存到数据库中:
new_comment.save()
更新模板
既然帖子有了评论功能,现在我们需要修改我们的list模板来适应这个功能。需要呈现如下功能
1 评论总数
2 显示评论的列表
3 显示一个表单给用户来添加新的评论
前面视图传递的comments参数。通过with comments.count as total_comments语句将评论的个数传递给total_comments.这样就能显示具体有多少个评论
{% with comments.count as total_comments %}
<h2>
{{ total_comments }} comment{{ total_comments|pluralize }}
现在加入评论列表我们使用{% for %}模板(template)标签(tag)来循环所有的评论。如果comments列为空我们会显示一个默认的信息,告诉我们的用户这篇帖子还没有任何评论。我们使用 {{ forloop.counter }}变量来枚举所有的评论,在每次迭代中该变量都包含循环计数。之后我们显示发送评论的用户名,日期,和评论的内容。
{% for comment in comments %}
<div class="comment">
<p class="info">
Comment {{ forloop.counter }} by {{ comment.name }}
{{ comment.created }}
</p>
{{ comment.body|linebreaks }}
</div>
{% empty %}
<p>还没有评论</p>
{% endfor %}
最后,你需要渲染表单或者显示一条成功的信息来代替之前的内容。在之前的代码后面添加如下内容
{% if new_comment %}
<h2>Your comment has been added.</h2>
{% else %}
<h2>添加新评论</h2>
<form action="/blog/{{ p.id }}/comment/" method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<input type="submit" value="增加评论">
</form>
{% endif %}
如果new_comment对象存在,我们会展示一条成功信息因为成功创建了一条新评论。否则,我们用段落<p>元素渲染表单中每一个字段
下面来测试下功能:
1 进入博客,此时还没有评论,因此显示0个评论。在下面有添加评论的界面
2在评论表单中填入信息,点击增加评论。成功的话显示评论已经添加成功的页面
3 此时在回到帖子的页面,可以看到添加的评论
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库