最新消息:欢迎光临 魔力 • Python!大家可以点开导航菜单中的【学习目录】,这个目录类似图书目录,更加方便学习!

Django2练习项目:开发个人博客系统(8)

Django教程 小楼一夜听春语 2953浏览 0评论

这一篇教程,我们一起完成Django2个人博客系统的文章详情页面的内容部分。

文章详情页面包含文章主体内容、评论内容以及评论发布功能。

因为内容比较多,我们在这一篇先完成视图部分。

代码很长,不能一次全放进来,那样会引起不适。

所以,我一段一段的慢慢深入,大家一起感受这个过程。

首先,我们需要导入Django提供的DetailView类,这是详情通用视图。

示例代码:

from django.views.generic import ListView, DetailView

上方代码中,红色部分是新增内容。

然后,我们定义文章详情类继承自DetailView类,并设置文章详情的文章主体内容部分。

示例代码:

class ArticleDetail(DetailView):
    model = Article
    template_name = 'detail.html'

实际上,通过上方的代码,我们就可以结合URL设置以及模板呈现文章主体内容了。

不过,在文章详情页还需要显示评论内容。

评论内容的展现效果如下:

我们来分析一下。

这样的评论列表,并不是完全按评论的发布顺序排序。

顶级评论是按发布顺序,顶级评论下的回复是按照层级进行排序。

评论文章是顶级评论,回复一条文章的评论是二级评论,回复一条回复内容是三级评论,以此类推。

而评论数据存储到数据库时并不是按照层级存储,所以我们需要将这些评论按照层级关系重新排列顺序。

具体的思路如下:

  1. 遍历所有评论数据,如果是文章的评论(顶级)存入一个列表;
  2. 如果不是文章的评论(也就是回复他人评论的评论),以评论目标(父级评论)的id为键存入字典。
  3. 循环遍历所有顶级评论,并通过递归函数归纳每一组评论内容(一个顶级评论和与之相关的回复评论),递归函数的参数为父级评论。

递归的过程不太容易理解,简单为大家描述一下。

调用递归函数时,存储参数中传入的顶级评论到最终返回的评论列表,再通过这个顶级评论的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)

头像
发表我的评论
取消评论

表情

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网站 (可选)

网友最新评论 (2)

  1. 头像
    这节有些难度,需要好好琢磨。
    北国江城1年前 (2019-02-26)回复
  2. 头像
    😛 :mrgreen: 有些难度
    mygoldwings1年前 (2019-03-30)回复