django框架之BBS项目之评论功能

内容回顾
    1. BBS项目 CMS
        1. 登录
            1. form组件
            2. auth模块
            3. 验证码
        2. 注册
            1. form组件
                1. 生成html代码
                    直接for循环form_obj,就能够遍历所有字段
                2. 验证
                    1. 默认的那些验证
                    2. 正则的验证
                    3. 全局钩子做确认密码的验证
                    4. 判断用户名是否已经存在
                        1. input框失去焦点就发ajax到后端判断
                        2. form组件中使用局部钩子来判断    
                    
            2. auth模块 --> 扩展auth_user表 --> create_user()
                1. UserInfo这个类里面,avatar是一个FileField
                    avatar = models.FileField(upload_to="avatars/", default="avatars/default.png")
                2. 注意事项:
                    1. FileField保存的是一个路径,而不是一个文件
                    2. upload_to:具体保存的文件路径就会在media目录下
            3. 上传头像
                1. ajax如何上传文件
                2. Django中media的配置
                    1. settings.py中:
                        - MEDIA_URL:别名
                        - MEDIA_ROOT:给用户上传的所有文件指定一个存放目录
                    2. urls.py中:
                        from django.views.static import serve
                        from django.conf import settings
                        
                        url(r‘^media/(?P<path>.*)‘, serve, {"document_root": settings.MEDIA_ROOT})
        3. 博客首页
            1. 文章列表(排样式)
            2. 分页
                1. 封装的要彻底
                2. 封装后的结果要有普适性(url要写成配置项)
        4. 个人博客主页
            1. 分类
                1. 文章分类
                2. 文章标签
            2. 日期归档
                1. 日期格式化函数    --> MySQL内置的函数都有哪一些?      --> 《漫画数据库》
                    1. MySQL:DATE_FORMAT(‘字段‘, ‘格式‘)
                    2. sqlite:strftime(‘格式‘, ‘字段‘)
                
                2. ORM中如何执行原生的SQL语句
                    1. 使用extra()在执行ORM查询的同时,嵌入一些SQL语句
                    2. 直接执行原生SQL语句
                        from django.db import connection
                        cursor = connection.cursor()
                        cursor.execute(‘select id from userinfo;‘)
                        cursor.fetchall()    
                3. 分组聚合
                    QuertySet.annotate()  --> 分组,前面查的是什么字段就按什么字段分组        
                    QuertySet.aggregate() --> 聚合,给QuerySet中的每个对象多一个属性
                    
                4. 4合1路由
                    不同的路由可以使用同一个视图函数!!! --> 视图函数中通过参数的不同,实现不同的功能
        5. 文章详情页
            1. 母板继承
            2. inclusion_tag
                1. 返回一段HTML代码,用数据填充的HTML代码
                2. 具体的写法
                    1. 在app下面创建一个名为 templatetags 的 Python Package
                    2. 在上面的包中创建一个 py文件
                    3. 按照inclusion_tag的格式要求写功能函数
                        
                        from django import template
                        register = template.Library()
                        
                        @register.inclusion_tag(file=‘xx.html‘)
                        def show_menu(*arg):
                            ...
                            return {"k1": "v1"}
                            (xx.html中使用k1这个变量)    
            3. 点赞
                1. ajax发送点赞的请求
                    1. 点赞必须是登录用户,没登录跳转到登录页面
                    2. 不能给自己的文章点赞
                    3. 一个用户只能给一篇文章点一次赞或踩一次
                
                2. 后端创建点赞记录(事务操作)
                    1. 创建新的点赞记录
                    2. 去对应的文章表里把点赞数更新一个
                3. ORM事务操作
                    from django.db import transaction
                    
                    with transaction.atomic():
                        sql1;
                        sql2;
                        
                4. Django模板语言里面的JS代码
                    如何在js中引用模板语言的变量,注意加引号!!!

接下来就开始写评论区的功能了,首先就是在页面布局:

我们希望吧页面布局成这个样式:

在bootstrap找到样式之后,作相应的改动:我们先想一下,在这个区域需要哪些数据,首先就是评论发表的时间,评论的作者,还有评论的内容。所以在文章详情页面的试图函数中应该传一些comment的参数。之后再页面中,通过for循环,逐个展示评论:

<!--评论展示区 开始-->
    <h4>评论</h4>
    <div class="list-group comment-list">
        {% for comment in comment_list %}
            <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#{{ forloop.counter }}楼</span>
                    <span>{{ comment.create_time|date:‘Y-m-d H:i‘ }}</span>
                    <span>{{ comment.user.username }}</span>
                    <span></span>
                </h4>
                <p class="list-group-item-text">{{ comment.content }}</p>
            </div>
        {% endfor %}
    </div>
    <!--评论展示区 结束-->

接下来就是发表评论的区域了:

同样是先布局,然后html代码:

<!--发表评论区 开始-->
    <h4>发表评论</h4>
    <div>昵称:
        <input type="text"value="{{ request.user.username }}" disabled>
    </div>
    <div>
        <p>评论内容:</p>
        <textarea cols="60" rows="10"></textarea>
    </div>
    <div>
        <button class="btn btn-success">提交</button>
    </div>
    <!--发表评论区 结束-->

接下来就是发送ajax请求了。

我们能够很容易的写出来这步:

 //给评论按钮绑定点击事件
    $(‘#submit-comment‘).click(function () {
        var userid = ‘{{ request.user.id }}‘;
        var articleid = ‘{{ article_obj.id }}‘;
        var content = $(‘#new-comment‘).val();
        var csrf_token = $(‘[name="csrfmiddlewaretoken"]‘).val();
        $.ajax({
            url:‘/comment/‘,
            type:‘post‘,
            data:{
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
            }
        })
    })
试图函数也可以这样写;

def comment(request):
    if request.method == ‘POST‘:
        res = {‘code‘:0}
        user_id = request.POST.get(‘user_id‘)
        article_id = request.POST.get(‘article_id‘)
        content = request.POST.get(‘content‘)           with transaction.atomic():         # 1.先去创建新评论            comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)         # 2.再去更新该文章的评论数            models.Article.objects.update(comment_count=F(‘comment_count‘)+1)
   return JsonResponse(res)

这样基本的评论功能已经写出来了,给文章评论之后,刷新之后在页面上就能够展示出评论内容,

但是我们实际的评论不是这样的,当我们评论之后,评论内容就会马上出现在展示区,不用通过刷新。这一步怎么实现呢?

这就要求我们在发送请求成功之后的success函数中将它通过js操作展示出来,说白了就是在原来评论展示区的下面再添加一个展示区。所以试图函数要返回一些数据:

views.py代码:

def comment(request):
    if request.method == ‘POST‘:
        res = {‘code‘:0}
        user_id = request.POST.get(‘user_id‘)
        article_id = request.POST.get(‘article_id‘)
        content = request.POST.get(‘content‘)          with transaction.atomic():         # 1.先去创建新评论            comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)         # 2.再去更新该文章的评论数            models.Article.objects.update(comment_count=F(‘comment_count‘)+1)
    res[‘data‘] = {       ‘id‘:comment_obj.id,       ‘username‘:comment_obj.user.username,       ‘content‘:comment_obj.content,       ‘create_time‘:comment_obj.create_time.strftime("Y-m-d") # 这部如果看不懂的话就去复习一下那三种时间格式的相互转化 } 

    return JsonResponse(res)

在说js操作代码之前,我们先来复习一个知识:就是js中的字符串格式化输出。

 # 给评论按钮绑定点击事件$(‘#submit-comment‘).click(function () {
        var userid = ‘{{ request.user.id }}‘;
        var articleid = ‘{{ article_obj.id }}‘;
        var content = $(‘#new-comment‘).val();
        var csrf_token = $(‘[name="csrfmiddlewaretoken"]‘).val();
        $.ajax({
            url:‘/comment/‘,
            type:‘post‘,
            data:{
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
                if(res.code===0){
                    var data = res.data
                    //先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一
                    var num = $(‘.comment-list>div‘).length + 1;
                    //创建评论成功后,通过js在评论区列表在添加一条评论
                    var commenthtml = `
                    <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#${ num }楼</span>
                    <span>${ data.create_time }</span>
                    <span>${ data.username }</span>
                    <span></span>
                </h4>
                    <p class="list-group-item-text">${ data.content }</p>
                </div>
                    `
                    //在原来的评论列表后面添加一条
                    $(‘.comment-list‘).append(commenthtml)
                    //情空 textarea
                    $(‘#new-comment‘).val(‘‘)
                }
            }
        })
    })

上面写的是添加父评论。

接下来添加子评论,就是回复的部分了:

博客园中当我们点击回复按钮时,评论区会显示这样:

分为两部:当我们点击回复标签时,光标就会聚焦在评论区,并且出现了@xxx

这个如何实现呢?

$(‘.replay‘).click(function () {
        //光标聚焦在textarea
        //出现@xxx
        var replayname = $(this).prev().text() //取到当前标签的前一个标签的文本
        $(‘#new-comment‘).focus().val(‘@‘+replayname+‘\n‘)
    })

comment表里有parent_comment字段,我们应该怎么取到这个字段的id呢?

当我们点击提交的时候,我们不管有没有父评论都给后端传一个parent_id,我们给评论的那个div加一个自定义的id

<div href="#" class="list-group-item" my_id="{{ comment.id }}">
<!--评论展示区 开始-->
    <h4>评论</h4>
    <div class="list-group comment-list">
        {% for comment in comment_list %}
            <div href="#" class="list-group-item" my_id="{{ comment.id }}">
                <h4 class="list-group-item-heading comment-header">
                    <span>#{{ forloop.counter }}楼</span>
                    <span>{{ comment.create_time|date:‘Y-m-d H:i‘ }}</span>
                    <span>{{ comment.user.username }}</span>
                    <span></span>
                </h4>          {% if comment.parent_comment %}                        <span style="display: block">@{{ comment.parent_comment.user.username }}</span>                        <p class="list-group-item-text well">                            {{ comment.parent_comment.content }}                        </p>                  {% endif %}
                <p class="list-group-item-text">{{ comment.content }}</p>
            </div>
        {% endfor %}
    </div>
    <!--评论展示区 结束-->

那么我们如何区分谁是父评论谁是子评论呢?当我们点击回复的时候,产生的评论就是子评论,直接点击提交就是父评论,那我们应该怎么操作呢?

我们把这个自定义的id添加到提交的按钮上,当我们点击提交的按钮是进行判断,如果这个id存在,就说明是子评论,否则就是父评论。

  //点击回复按钮时的绑定事件$(‘.replay‘).click(function () {
        //光标聚焦在textarea
        //出现@xxx
        var replayname = $(this).prev().text() ;//取到当前标签的前一个标签的文本
        $(‘#new-comment‘).focus().val(‘@‘+replayname+‘\n‘);
        //把当前评论的id值,存到提交的按钮中
        var pID = $(this).parent().parent().attr(‘my-id‘);
        $(‘#submit-comment‘).data(‘pid‘,pID)
    })
 //给评论按钮绑定点击事件
    $(‘#submit-comment‘).click(function () {
        var userid = ‘{{ request.user.id }}‘;
        var articleid = ‘{{ article_obj.id }}‘;
        var content = $(‘#new-comment‘).val();
        var csrf_token = $(‘[name="csrfmiddlewaretoken"]‘).val();
        var parentId = $(this).data(‘pid‘) || ‘‘;
        if(parentId){        //因为在添加自评论时,会出现@xxx的东西所以我们按照索引把他去除
            content = content.slice(content.indexOf(‘\n‘)+1,);
        }
        $.ajax({
            url:‘/comment/‘,
            type:‘post‘,
            data:{
                parent_id:parentId,
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
                if(res.code===0){
                    var data = res.data
                    //先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一
                    var num = $(‘.comment-list>div‘).length + 1;
                    //创建评论成功后,通过js在评论区列表在添加一条评论
                    var commenthtml = `
                    <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#${ num }楼</span>
                    <span>${ data.create_time }</span>
                    <span>${ data.username }</span>
                    <span></span>
                </h4>
                    <p class="list-group-item-text">${ data.content }</p>
                </div>
                    `;
                    //在原来的评论列表后面添加一条
                    $(‘.comment-list‘).append(commenthtml);
                    //情空 textarea
                    $(‘#new-comment‘).val(‘‘);            //当我们点击提交按钮时,应该把自定义的id去掉,不然下一次点击提交的时候,还是有这个id值
                    $("#submit-comment").removeData("pid");
                }
            }
        })
    });

我们后端也能拿到parent_id。

def comment(request):
    if request.method == ‘POST‘:
        res = {‘code‘:0}
        user_id = request.POST.get(‘user_id‘)
        article_id = request.POST.get(‘article_id‘)
        content = request.POST.get(‘content‘)
        parent_id = request.POST.get("parent_id")
        #创建评论
        with transaction.atomic():
            # 1.先去创建新评论
            if parent_id:
                #添加自评论
                comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content,parent_comment_id=parent_id)
            else:
                #添加父评论
                comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id, content=content)
            # 2.再去更新该文章的评论数
            models.Article.objects.update(comment_count=F(‘comment_count‘)+1)
        res[‘data‘] = {
            ‘parent_id‘:parent_id,
            ‘id‘:comment_obj.id,
            ‘username‘:comment_obj.user.username,
            ‘content‘:comment_obj.content,
            ‘create_time‘:comment_obj.create_time.strftime("Y-m-d")
        }
        return JsonResponse(res)

这样添加的评论还不够完美,就是添加的评论没有回复这个功能,

 //给评论按钮绑定点击事件
    $(‘#submit-comment‘).click(function () {
        var userid = ‘{{ request.user.id }}‘;
        var articleid = ‘{{ article_obj.id }}‘;
        var content = $(‘#new-comment‘).val();
        var csrf_token = $(‘[name="csrfmiddlewaretoken"]‘).val();
        var parentId = $(this).data(‘pid‘) || ‘‘;
        if(parentId){
            //因为在添加自评论时,会出现@xxx的东西所以我们按照索引把他去除
            content = content.slice(content.indexOf(‘\n‘)+1,);
        }
        $.ajax({
            url:‘/comment/‘,
            type:‘post‘,
            data:{
                parent_id:parentId,
                user_id:userid,
                article_id:articleid,
                content:content,
                csrfmiddlewaretoken:csrf_token,
            },
            success:function (res) {
                console.log(res)
                if(res.code===0){
                    var data = res.data
                    //先计算原来.comment-list的后代有几个div,即有几个人评论,然后再加一
                    var num = $(‘.comment-list>div‘).length + 1;
                    //创建评论成功后,通过js在评论区列表在添加一条评论
                    var commenthtml = `
                    <div href="#" class="list-group-item">
                <h4 class="list-group-item-heading comment-header">
                    <span>#${ num }楼</span>
                    <span>${ data.create_time }</span>
                    <span>${ data.username }</span>
                    <span class="pull-right replay">回复</span>
                </h4>
                    <p class="list-group-item-text">${ data.content }</p>
                </div>
                    `;
                    //在原来的评论列表后面添加一条
                    $(‘.comment-list‘).append(commenthtml);
                    //情空 textarea
                    $(‘#new-comment‘).val(‘‘);
                    //当我们点击提交按钮时,应该把自定义的id去掉,不然下一次点击提交的时候,还是有这个id值
                    $("#submit-comment").removeData("pid");
                }
            }
        })
    });

添加回复这个按钮后,不能实现点击,这就用到了事件委托,当一个事件不能完成时,我们把它委托给他的父标签做将来的动作。

    //给回复按钮绑定事件
    //$(‘.replay‘).click(function () {
    //事件委托,
     $(‘.comment-list‘).on(‘click‘,‘.replay‘,function () {
        //光标聚焦在textarea
        //出现@xxx
        var replayname = $(this).prev().text() ;//取到当前标签的前一个标签的文本
        $(‘#new-comment‘).focus().val(‘@‘+replayname+‘\n‘);
        //把当前评论的id值,存到提交的按钮中
        var pID = $(this).parent().parent().attr(‘my-id‘);
        $(‘#submit-comment‘).data(‘pid‘,pID)
    })

这就是完整的代码了

不懂得地方看视频,(看视频day79. 004)

上面设计到的知识点,jquery中的data方法,就是我们可以给任意一个jQuery对象添加一个值。

js中的三元运算:

还有就是事件委托

原文地址:https://www.cnblogs.com/yb635238477/p/9508458.html

时间: 2024-09-30 06:33:37

django框架之BBS项目之评论功能的相关文章

django框架之BBS项目之文章详情和点赞

内容回顾    1. 个人博客主页        1. 分类展示            - 文章分类(2)                文章(Article)表和分类(Category)表                1. 先找这个人的博客有哪些文章分类                2. 每个文章分类下的文章总数                3. 基于对象的查询 category_obj.article_set.all().count()                         

Django框架的安装,项目创建

目录 Django框架的安装,项目创建 方法安装 Django版本选择 1.11.21(最新LTS版) django管理目录 命令行创建项目 django项目 命令行启动 (必须在项目文件下执行) pychrm创建项目 pychrm启动项目 配置文件相关设置(重启生效) Django框架的安装,项目创建 方法安装 Django版本选择 1.11.21(最新LTS版) django管理目录 mysite/ ├── manage.py # 管理文件 └── mysite # 项目目录 ├── __i

Python Django框架实现商城项目源码加设计文档和注释

Python Django框架实现商城项目源码加设计文档和注释 链接:https://pan.baidu.com/s/1yN2iBgx3zmpTkoY8u1LWRg 提取码:lfsx 非常完整的django项目源码,分享给撸友们,不管是学习还是深造,都是可以学习借鉴的!! 原文地址:https://www.cnblogs.com/zyxlovesjy/p/12115491.html

博客项目实现文章评论功能(重点是评论回复)

我开发的博客网站的地址:http://118.89.29.170/RiXiang_blog/ 博客项目代码github:https://github.com/SonnAdolf/sonne_blog 有了我的已成型的项目和代码,可以更容易理解这篇文章. 本篇文章记录下自己博客项目评论功能实现的全过程,重点其实是评论回复功能. [一,写评论] 写评论部分我没有使用富文本编辑器,只是单纯地使用了textarea标签,所以后台不需要作html标签的白名单检验(关于防范xss攻击,可以看我之前的一篇文章

一 Django框架介绍——用pycharm创建Django项目

Django框架介绍 Django是一个开放源代码的Web应用框架,由Python写成.采用了MVC的软件设计模式,即模型M,视图V和控制器C.它最初是被开发来用于管理劳伦斯出版集团旗下的一些以新闻内容为主的网站的,即是CMS(内容管理系统)软件.并于2005年7月在BSD许可证下发布. 这套框架是以比利时的吉普赛爵士吉他手Django Reinhardt来命名的. 更多Django框架http://code.ziqiangxuetang.com/django/django-qrcode.htm

全栈项目|小书架|小程序端-评论功能实现

效果图 发布评论 发布评论的入口在图书详情页面,点击 写评论 按钮之后跳转到发布评论页面. wxml布局比较简单了,目前还没有添加图片评论功能,也没有子评论功能,所以伪代码就比较简单了: <view class="comment-container"> <!-- book name --> <view class="book-name"> <text>{{bookInfo.name}}</text> <

django框架预备知识

内容: 1.web预备知识 2.django介绍 3.web框架的本质及分类 4.django安装与基本设置 1.web预备知识 HTTP协议:https://www.cnblogs.com/wyb666/p/9383077.html 关于web的本质:http://www.cnblogs.com/wyb666/p/9034042.html 如何自定义web框架:http://www.cnblogs.com/wyb666/p/9038644.html 了解cookie和session:https

django框架之模型

ORM简介 ORM,全拼Object-Relation Mapping,中文意为对象-关系映射,是随着面向对象的软件开发方法发展而产生的.面向对象的开发方法是当今企业级应用开发环境中的主流开发方法,关系数据库是企业级应用环境中永久存放数据的主流数据存储系统.对象和关系数据是业务实体的两种表现形式,业务实体在内存中表现为对象,在数据库中表现为关系数据.内存中的对象之间存在关联和继承关系,而在数据库中,关系数据无法直接表达多对多关联和继承关系.因此,对象-关系映射ORM系统一般以中间件的形式存在,主

BBS项目-01

目录 BBS项目 BBS开发流程: BBS表格创建: BBS项目 BBS开发流程: BBS项目: 开发流程: 需求分析 草拟一些项目的大致技术点和流程 架构设计 架构师(框架 语言 数据库 缓存数据库 表设计 拆分功能 项目的报价 分组开发 任务 按模块功能分的 组长在拆分功能 每个组员写几个小功能 需要提前测试一下有没有bug 交互测试 运维上线 BBS表格创建: from django.db import models from django.contrib.auth.models impo