django树形结构之博客评论案例(带回复功能) - 基础篇

image.png

前言说明

这里先以博客的评论模板展开实战,基础班是最基本的实现了评论和回复评论功能,但是在UI展示方面,没有能实现树状的层级结构,而且是回复评论的记录都在对应的顶层评论之下进行缩进

先看效果图

django-comment-02.png

模型设计

这里因为是做Demo介绍,所以把文章评论放到了一个应用中去,常规情况下为了应用的复用,建议是拆分成两个独立的应用

1、模型代码

# comment/models.py
class Post(models.Model):
    """
    1、用于测试,不用给全所有属性
    2、常规建议文章是独立的APP,评论是独立的APP,这里为了测试放到了一起
    """
    title = models.CharField(max_length=128, verbose_name="文章标题")

    def __str__(self):
        return self.title 


class Comment(models.Model):
    post = models.ForeignKey(Post, on_delete=models.DO_NOTHING, verbose_name="评论的文章")
    comment_body = models.TextField(verbose_name="评论的内容")
    comment_time = models.DateTimeField(default=timezone.now, verbose_name="评论时间")
    comment_user = models.CharField(max_length=32, verbose_name="评论人")
    comment_email = models.EmailField(verbose_name="评论者邮箱")
    comment_url = models.URLField(blank=True, null=True, verbose_name="评论者URL")
    # 关联自身
    parent_comment = models.ForeignKey('self', null=True, on_delete=models.DO_NOTHING, verbose_name="回复的评论")

    def __str__(self):
        return f'{self.comment_user.username} 评论说: {{ self.comment_content[:20] }}'

视图设计

视图函数代码

# comment/views.py
def index(request): 
    posts = Post.objects.all()  
    context = { 'posts': posts }
    return render(request,'comment/index.html',context=context)


def detail(request, id):
    post = Post.objects.get(pk=id)
    comments = Comment.objects.filter(post_id=id)
    form = CommentForm()
    context = { 'post': post, "comments": comments, "form": form}
    return render(request,'comment/detail.html',context=context)


def comment(request):
    comment_body = request.POST.get('comment_body')
    post_id = request.POST.get('post_id')
    pid = request.POST.get('pid')
    username = request.POST.get('comment_user')
    email = request.POST.get('comment_email')
    url = request.POST.get('comment_url')
    post = Post.objects.get(id=post_id)
    new_comment = Comment()
    new_comment.comment_body = comment_body
    new_comment.comment_user = username
    new_comment.comment_email = email 
    new_comment.comment_url = url 
    new_comment.post = post 

    if pid:
        new_comment.parent_comment_id = pid
    new_comment.save()

    # 评论成功跳转回当前详情页,是为了刷新当前页看到刚评论的内容
    return HttpResponseRedirect(reverse("comment:detail", args=(post_id)))

引入Form表单

因为是在学习Django,所以能用Django自带功能实现的,就优先使用Django功能

在template表单页展示时,可以自己写纯HTML页面,也可以使用 Django Form 表单来快速创建

Form表单代码

from django.forms import ModelForm, Textarea
from comment.models import Comment

class CommentForm(ModelForm):
    class Meta:
        model = Comment
        fields = ['comment_user', 'comment_email', 'comment_url', 'comment_body']

URL及Template模板

1、URL设计

# comment/urls.py
from django.urls import path
from comment import views

app_name = 'comment'
urlpatterns = [
    path('', views.index, name='index'),
    path('post//', views.detail, name='detail'),
    path('post/comment/', views.comment, name='comment'),
]

2、template模板,这里只有 index.html 和 detail.html

index.html是展示文章列表,为了友好的跳转到详情页去

detail.html 页面主要是演示 评论框、评论列表和回复功能, 因为文章只有title,所以重点在演示评论功能





    
    
    
    
    
    

    Document


    
发表评论
{% csrf_token %}
{{ form.comment_user }} {{ form.comment_user.errors }}
{{ form.comment_email }} {{ form.comment_email.errors }}
{{ form.comment_url }} {{ form.comment_url.errors }}

{{ form.comment_body }} {{ form.comment_body.errors }}
评论列表, 总 {{ comment_count }} 条评论
    {% for comment in comments %}
  • {{ comment.comment_user }} {{ comment.comment_time |date:'Y-m-d'}} 发表评论:

    {% if comment.parent_comment_id %}
    {{ comment.parent_comment.comment_body|linebreaks}}
    {% endif %}

    {{ comment.comment_body|linebreaks }}

  • {% empty %}

    暂无评论

    {% endfor %}

这里有一小段js代码,需要在文件head中引入 jquery ,目的有:
1、在点击Reply/回复 的时候聚焦到 评论框,同时这里还给回复的时候添加了默认的内容 @xxx

2、同时设置回复的内容的ID,也就是当前评论的父级评论的ID,为了是为了知道 回复的那条评论

知识点总结

1、引入了Django Form 表单,单独的Python文件定义,然后可以在template中快速创建响应的表单

2、一小段JS代码,实现回复时自动聚焦到评论框和设置父级评论的ID

3、在template中的模板表单 等post提交数据的地方,需要添加{% csrf_token %} 不然会报错,当然可以通过在post对应的待处理的视图函数上添加@csrf_exempt装饰器(忽略csrf校验) 对应的有个 csrf_protect 开启csrf校验

4、在comment视图函数中,注意需要判断父级评论id是否为空,来设定当前是回复的评论还是一般评论 ;同时注意评论成功之后进行跳转到当前详情页,查看当然评论的内容

问题和思考

从最开始的图片可以看到,虽然模型定义是符合树状结构 的,但是实际页面展示的时候却没有按照树状结构进行层级缩进 展示

因为在多层级的情况下,需要判断是不是叶子节点,而且还要用到递归处理。 写个递归很简单,但是又涉及到在template模板中进行数据展示,常规的函数无法使用,需要编写 标签或者过滤器才可以

那除了自己开发之外, 有没有更好的方案呢?

当然有,现在常用的是 django-mptt 第三包,另外一篇文章我们单独讲解 django-mptt

代码开源地址:https://gitee.com/colin5063/django_learning_v2/tree/django_blog_comment_v1/

你可能感兴趣的:(django树形结构之博客评论案例(带回复功能) - 基础篇)