创建一个评论系统
你将建立一个 评论系统,其中用户将能够评论帖子,去创建评论系统,你需要做下面的这些:
- 创建一个模型去保存评论。
- 创建提交评论的表单,并且验证输入数据。
- 添加处理表单并且在数据库中保存一个新评论的视图。
- 编辑帖子详情模板去显示评论列表,和添加新评论的表单。
1. 创建模型
首先,创建的一个模型去存储评论,在你的 blog
应用程序里面打开 models.py
文件,并且添加下面的这些代码:
class Comment(models.Model):
post = models.ForeignKey(Post,
on_delete=models.CASCADE,
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 f'Comment by {self.name} on {self.post}'
这是你的 Comment
模型。它包含一个 ForeignKey
来将一个评论与唯一的一个帖子联系起来。这个多对一关系定义在 Comment
模型中,因为每一个评论都在一个帖子中发表,并且每一个帖子可能有多个评论。
related_name
属性提供了一个 name
的属性,在关系中使用这个 name
属性可以返回一个关系对象。在定义这个之后,你可以使用comment.post
检索一个评论对象的帖子,并且使用 post.comments.all()
检索一个帖子的所有评论。如果你没有定义这个 related_name
属性,Django 将使用小写的模型名称,然后通过_set(即comment_set)去命名与 模型对象 相关联的对象 的关系,该关系已在其中定义。
你可以在这个链接学习更多关于 多对一关系。
你有包含一个 active
布尔字段,你可以手动的让不适当的评论失效。默认情况下,使用created
字段按时间顺序对评论进行排序。
新的 Comment
模型它现在仅仅被创建还没有同步创建到数据库中。运行下面的命令去生成一个新的迁移,思考新模型的创建:
python manage.py makemigrations
你可以看到下面的输出:
image.png
Django 在 blog
应用程序的 migrations
目录中生成了一个 00002_comment.py
文件。现在你需要创建相关的关系数据库模式并将修改应用到数据中。运行下面的命令应用现有迁移:
python manage.py migrate
你将得到输出包含下面的这行:
image.png
你刚刚创建的迁移已经被应用,现在在数据库中存在一个 blog_comment
表。
接下来,你在管理员站点中添加的你新模型,以通过一个简单的接口去管理评论。打开 blog
应用程序的 admin.py
文件,导入 Comment
模型,并且添加下面的 这个 ModelAdmin
类。
from .models import Post, Comment
@admin.register(Comment)
class CommentAdmin(admin.ModelAdmin):
list_display = ('name', 'email', 'post', 'created', 'active')
list_filter = ('active', 'created', 'updated')
search_fields = ('name', 'email', 'body')
通过 python manage.py runserver
命令去启动 开发者服务器,并且在你的浏览器中打开: http://127.0.0.1:8000/admin。 你将看到一个新的模型包含在 BLOG 部分。如图下面的屏幕快照:
这个模型现在被注册在 管理员站点中,你可以使用一个简单的接口去 管理 Comment
实例。
2. 为模型创建表单
你依然需要构建一个 表单去 让你在 博客帖子中使用评论。记住 Django 有两个基础类去创建表单,Form
和 ModelForm
。你以前使用了一个去让你可以通过 email 分享 帖子。在这个例子中,你将需要使用 ModelForm
,因为你必须在你的 Coment
模型中创建一个动态表单。编辑在你的 blog
应用程序中的 forms.py
文件,并且添加下面这些行:
from .models import Comment
class CommentForm(forms.ModelForm):
class Meta:
model = Comment
fields = ('name', 'email', 'body')
从一个模型中创建一个表单,您只需要在表单的Meta
类中指明要使用哪个模型来构建表单。Django 将内省模型并且为你动态的创建表单。
每个模型字段类型都有相应的默认表单字段类型。定义模型字段的方式将考虑到表单验证。默认情况下,Django 为每一个包含在模型中的字段创建创建一个 表单字段。但是,您可以使用fields
列表显式地告诉框架希望在表单中包括哪些字段,或者使用字段的exclude
列表定义希望排除哪些字段。为了你的 CommentForm
表单,将使用 name
, email
, body
字段,因为这些仅仅是用户能填写的字段。
3. 在视图中处理模型表单
你将使用 帖子详情 视图去实例化这个表单 并且去处理它。为了保持简单,编辑 views.py
文件,添加导入 Comment
模型 和 CommentForm
表单,并且修改 post_detail
视图,使它看起来像下面这样:
from .models import Post, Comment
from .forms import EmailPostForm, CommentForm
def post_detail(request, year, month, day, post):
post = get_object_or_404(Post, slug=post,
status='published',
publish__year=year,
publish__month=month,
publish__day=day)
# 这篇帖子的有效评论
comments = post.comments.filter(active=True)
new_comment = None
if request.method == 'POST':
comment_form = CommentForm(data=request.POST)
if comment_form.is_valid():
# 创建评论对象但是现在没有保存到数据库中
new_comment = comment_form.save(commit=False)
# 将当前 帖子 分配给 评论
new_comment.post = post
# 保存评论到数据库中
new_comment.save()
else:
comment_form = CommentForm()
return render(request,
'blog/post/detail.html',
{ 'post': post,
'comments': comments,
'new_comment': new_comment,
'comment_form': comment_form})
让我们回顾一下添加到视图中的。你使用这个 post_detail
使用去显示这个 帖子 和 它的评论。你添加了一个 查询集 为这个 帖子 去检索所有有效的评论。 如下:
comments = post.comments.filter(active=True)
从 post
对象去构建这个查询集,而不是直接为 Comment
模型创建一个 查询集。 您可以利用post
对象来检索相关的Comment
对象。您可以使用管理器对相关对象使用Comment
模型中关系的related_name
属性定义为comments
。您可以使用相同的视图让您的用户添加新的评论。通过将new_comment
变量设置为None
来初始化它。当一个新的评论被创建的时候使用这个变量。
如果这个视图通过一个 GET
请求被调用,你将通过 comment_form = CommentForm()
创建一个表单实例。 如果请求是通过 POST
完成的,你将使用从表单中提交的数据去实例化这个表单,并且使用 is_valid()
方法去验证它。如果表单是非法的,你将呈现带有验证错误的表单。如果表单时合法的,你可以采取以下行动:
- 你通过调用表单的
save()
方法去创建一个新的Comment
对象,并且将它分配到new_comment
变量中,如下所示:
new_comment = comment_form.save(commit=False)
save()
方法创建表单链接的模型实例,并将其保存到数据库中,如果你使用 commit=False
调用它,你创建这模型实例,但是现在不在数据库中保存它。当您希望在最终保存之前修改对象时,这就很方便了,这就是您接下来要做的事情。
save()
方法可用于ModelForm
,但不能用于Form
实例,因为它们没有链接到任何模型。
(译者注: ModelForm 里面是包含了一个数据库实例了的,但是 Form 是没有包含的,也就是没有保存到数据库中的)
-
您将当前的帖子分配给您刚刚创建的评论:
new_comment.post = post
通过做这些,你指定这个新的评论属于这个帖子。 -
最后,你通过调用
save()
方法 保存这个新的评论到数据库中。
new_comment.save()
您的视图现在可以显示和处理新的评论了。
4. 在帖子详情模板中添加评论
你创建函数去为一个帖子管理评论。现在你需要调整 post/detail.html
模板,去做下面这些事情:
- 为一个帖子显示评论的总数
- 显示 评论的列表
- 显示一个表单为用户去添加一个新评论。
首先,你将添加评论总数。打开post/detail.html
模板并且在 content
快中添加下面代码:
{% with comments.count as total_comments %}
<h2>
{{ total_comments }} comment {{ total_comments|pluralize }}
</h2>
{% endwith %}
你可以在 模板中使用 Django 的 ORM,执行查询集的 comments.count()
。注意,Django 模板语言不是使用括号的方式调用方法的。{% with %}
标签允许你为一个新的变量赋值,该变量将一直到 {% endwith %} 标签结束。
模板标签的
{% with %}
对于避免多次访问数据库或访问昂贵的方法非常有用。
你可以使用 pluralize
模板过滤器为 单词 "comment," 根据 total_comments
的值显示一个复数后缀。模板过滤器将其应用于的变量的值作为输入,并返回一个计算过的值。我们将发现在 第三章 扩展博客应用程序 发现更多模板过滤器。
这个 pluralize
模板过滤器的值不等于1,将返回一个 带有字母 's' 的字符串。前面的文本将被显示为 0 comments, 1 comment, N comments。 Django 有大量的模板标签和过滤器,它们能用来帮助你使用一些方法显示你想要的信息。
现在让我们来包括评论列表。在 post/detail.html
模板中前面的代码里添加下面这些行:
{% 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>There are no comments yet.</p>
{% endfor %}
你使用 {% for %}
模板标签去循环遍历评论。如果 评论列表 为空你将显示一个默认信息,通知你的用户这篇文章还没有评论。你通过 {{ forloop.counter }}
变量枚举 评论,它每次迭代包含一个循环计数器。这时你显示发布评论的用户的名字,日期,还有评论的主体。
最后,你需要程序这个表单或者当它被提交成功后显示一个 成功 消息实例。在前面的代码下面添加下面这些行:
{% if new_comment %}
<h2>Your comment has been added.</h2>
{% else %}
<h2>Add a new comment</h2>
<form method="post">
{{ comment_form.as_p }}
{% csrf_token %}
<p><input type="submit" value="Add comment"></p>
</form>
{% endif %}
这代码很简单明了,如果 new_comment
对象存在,你显示一个成功的消息,因为评论被成功创建。其他情况下,你通过 一个 段落标签 <p>元素 为每一个字段,以及 作为 POST 请求必须参数的 CSRF token 呈现这个表单。
在你的浏览器中打开 http://127.0.0.1:8000/blog/ , 并且点击一个 帖子的标题,去得到它的详情页面。你将看到一些像下面快照的东西:
使用表单添加一些评论,它们应该按照时间顺序出现在你的文章下面,如下:
image.png
在你的浏览器中打开 http://127.0.0.1:8000/admin/blog/comment/, 你将看到带有被你创建的评论列表的管理员页面。 点击其中它们的一个名字并且编辑它,取消 Active 复选框,并且点击 Save 按钮,你将再次重定向到评论列表,并且 ACTIVE列将为这个评论显示一个 不可用图标。 它看起来像下面快照的第一个评论:
如果你返回到帖子详情视图,你将注意到,这这个不可用评论不再显示了。它也不被计入到评论的总数里面了。感谢这个 active
字段,你可以取消不合法的评论,并且避免在你的帖子中显示它们。
网友评论