这一篇教程,我们一起完成Django2个人博客系统的文章详情页面的内容部分。
文章详情页面包含文章主体内容、评论内容以及评论发布功能。
因为内容比较多,我们在这一篇先完成视图部分。
代码很长,不能一次全放进来,那样会引起不适。
所以,我一段一段的慢慢深入,大家一起感受这个过程。
首先,我们需要导入Django提供的DetailView类,这是详情通用视图。
示例代码:
from django.views.generic import ListView, DetailView
上方代码中,红色部分是新增内容。
然后,我们定义文章详情类继承自DetailView类,并设置文章详情的文章主体内容部分。
示例代码:
class ArticleDetail(DetailView): model = Article template_name = 'detail.html'
实际上,通过上方的代码,我们就可以结合URL设置以及模板呈现文章主体内容了。
不过,在文章详情页还需要显示评论内容。
评论内容的展现效果如下:
我们来分析一下。
这样的评论列表,并不是完全按评论的发布顺序排序。
顶级评论是按发布顺序,顶级评论下的回复是按照层级进行排序。
评论文章是顶级评论,回复一条文章的评论是二级评论,回复一条回复内容是三级评论,以此类推。
而评论数据存储到数据库时并不是按照层级存储,所以我们需要将这些评论按照层级关系重新排列顺序。
具体的思路如下:
- 遍历所有评论数据,如果是文章的评论(顶级)存入一个列表;
- 如果不是文章的评论(也就是回复他人评论的评论),以评论目标(父级评论)的id为键存入字典。
- 循环遍历所有顶级评论,并通过递归函数归纳每一组评论内容(一个顶级评论和与之相关的回复评论),递归函数的参数为父级评论。
递归的过程不太容易理解,简单为大家描述一下。
调用递归函数时,存储参数中传入的顶级评论到最终返回的评论列表,再通过这个顶级评论的id从字典中获取它的所有回复评论,然后进行递归;此时再次调用递归函数,存储顶级评论的第一个回复评论,在通过这个回复评论的id获取这个回复评论的所有回复评论,再次递归,以此类推,直到找不到新的一层回复评论,结束递归。
综上所述,我们需要在文章详情类(ArticleDetail)中定义相关的函数。
示例代码:
def comment_sort(self, comments): # 评论排序函数 self.comment_list = [] # 排序后的评论列表 self.top_level = [] # 存储顶级评论 self.sub_level = {} # 存储回复评论 for comment in comments: # 遍历所有评论 if comment.reply == None: # 如果没有回复目标 self.top_level.append(comment) # 存入顶级评论列表 else: # 否则 self.sub_level.setdefault(comment.reply.id, []).append(comment) # 以回复目标(父级评论)id为键存入字典 for top_comment in self.top_level: # 遍历顶级评论 self.format_show(top_comment) # 通过递归函数进行评论归类 return self.comment_list # 返回最终的评论列表 def format_show(self, top_comment): # 递归函数 self.comment_list.append(top_comment) # 将参数评论存入列表 try: self.kids = self.sub_level[top_comment.id] # 获取参数评论的所有回复评论 except KeyError: # 如果不存在回复评论 pass # 结束递归 else: # 否则 for kid in self.kids: # 遍历回复评论 self.format_show(kid) # 进行下一层递归
完成了这两个函数之后,我们就可以从数据库中获取当前文章的所有评论内容,进行归类排序,并整合到发送给模板的数据中。
示例代码:
def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) comments = Comment.objects.filter(article=self.kwargs['pk']) # 通过文章id查询评论内容 context['comment_list'] = self.comment_sort(comments) # 将排序归类后的文章列表存入传送到模板的数据中 return context
在上方代码中,标红部分就是关于评论的显示内容。
另外,在文章详情页,我们还需要提供评论的功能。
评论功能的表单我们可以通过“ModelForm”进行创建。
提示:实际上,在之后的教程中,因为使用了JQuery提交评论数据,这个表单并没有进一步的作用,之所以在这里这么做,是为了给大家介绍一些更多的内容。
在模板中我们结合了Bootstrap和JQuery,当我们使用Django表单时,如何让自动生成的表单元素使用Bootstrap的样式呢?如何让JQuery能够关联表单的元素呢?
新建一个表单文件“forms.py”,然后编写代码。
示例代码:
from django import forms from .models import Comment class CommentForm(forms.ModelForm): class Meta: model = Comment fields = ['name', 'email', 'content'] # 需要呈现在页面上的表单元素 widgets = { # 定义字段对应的表单元素以及属性 'name': forms.TextInput(attrs={'id': 'name', 'class': 'form-control', 'placeholder': '请输入昵称'}), 'email': forms.EmailInput(attrs={'id': 'email', 'class': 'form-control', 'placeholder': '请输入邮箱'}), 'content': forms.Textarea(attrs={'id': 'content', 'class': 'form-control', 'placeholder': '请输入评论内容'}), }
在上方代码中,我们通过“widgets”定义了字段对应的表单元素,并且设置了属性。
属性中定义的“id”,是为了方便JQuery获取以及控制元素的属性与值。
而属性中定义的“class”则是用来调用Bootstrap。
完成上方代码之后,我们就可以在视图中使用这个表单了。
示例代码:
from .forms import CommentForm
def get_context_data(self, **kwargs): ...省略部分代码... comment_form = CommentForm() # 创建评论表单对象 context['comment_form'] = comment_form # 将表单对象传送到模板的数据中 return context
这篇教程就到这里,在下一篇教程中,我们将基于这个视图进行模板的创建。
转载请注明:魔力Python » Django2练习项目:开发个人博客系统(8)