Django,Ajax,Vue实现文章评论功能 𖇍

原文:
http://blog.gqylpy.com/gqy/440

置顶:来自一名75后老程序员的武林秘籍——必读(博主推荐)



来,先呈上武林秘籍链接:http://blog.gqylpy.com/gqy/401/

你好,我是一名极客!一个 75 后的老工程师!

我将花两分钟,表述清楚我让你读这段文字的目的!

如果你看过武侠小说,你可以把这个经历理解为,你失足落入一个山洞遇到了一位垂暮的老者!而这位老者打算传你一套武功秘籍!

没错,我就是这个老者!

干研发 20 多年了!我也年轻过,奋斗过!我会画原理图,会画 PCB,会模拟,会数字!玩过 PLC,玩过单片机,会用汇编,会用 C!玩过 ARM,比如
PLC,STM32,和时下正在起飞的 NXP RT1052!搞过 DSP,比如 TMS320F28335!搞过 FPGA,不管 Xilinx 还是 Altera,也不管是 Verilog 还是
VHDL,或者直接画数字电路图!我懂嵌入式系统,比如 uCOS 和 Linux!我懂开源的硬件,比如 Arduino
和树莓派!我也搞软件,学了一堆上位机的语言C#,JAVA,Python,Kotlin,Swift!会写爬虫工具,又自学写APP,不管Android 还是 IOS!

可是这一切有什么用呢?土鸡瓦狗!不值一提!干技术的永远就是最苦逼的那个人!

我相信看到这里的你,应该是个 IT
圈的人!或许是个学生,在学习某个技能!或者是个初入职场的年轻人,在啃某个技术!或者是个工程师,被项目困住,想找个资料快速突破阻碍!反正不管怎么样,你们都不会是泛泛之辈,不可能轻易交出智商税!

所以我把这份资料放进我的收费资源里,以证明接下去我要跟你讲的这本武功秘籍是可以真真实实的帮你赚到钱的!

我不知道叫它什么好,我把它写的像武林秘籍!所以我姑且叫它《武林秘籍》或者叫《赚钱秘籍》!

《武林秘籍》里封装了一个本人近期创造的一个可以一劳永逸的赚钱方法!你可以理解为躺着赚钱,或者挂机赚钱!请你放心,不是让你去违法!

我是一个IT男,从来不忽悠别人,这是我做人的原则。若此举能帮助你付起房子首付与月供,减轻一些目前高房价的压力,何乐而不为呢!

我提取里边几个要点:

  1. 将你手里有的资源按照说明书一步一步完成所有动作就可以躺着赚钱。
  2. 你不可能不劳而获,但是用这个方法确实是可以一劳永逸!
  3. 我用业余时间操作这个项目三个月,现在每天稳定收入300+。
  4. 里边会告诉你哪些是资源,怎么源源不断的获取资源。
  5. 里边会告诉你怎么获取爆炸的流量。
  6. 里边会告诉你很多黑技能(不是干坏事)。
  7. 总之,里边字字如金,有些东西我不告诉你可能这辈子都不会知道!

交了这波智商税,你的能力会爆涨,我说的不是你的专业能力,而是在这个社会生存的基础能力!

以上所有的东西可以规为武功的招式,但如果你想短期就实现目标,我还在说明书的最后留下了一些现成资源的下载链接,包括一些稀缺的资源,保证物有所值。这部分内容可以规为内功,继不继承由你自已决定!

好了,最后跟所有的老者不一样的是:这个老人要问你收取一点点小费,才会把无比珍贵的秘籍交到你手中!

以下是付款链接,付款后你将获取《武林秘籍》的访问密码。随后你将解锁另外一个谋生技能,在工作挣着死工资的同时,该技能也能同时帮你赚另一份钱,终身受用!

http://www.gqylpy.com/get_wlmj_pwd

能在此遇见是我们的缘分,我愿意帮助你,祝你取得成功!

传说中的武林秘籍:http://blog.gqylpy.com/gqy/401/

Django评论

评论复杂的地方在于需要实现点击提交评论后评论内容需要立刻出现在下面,还要保持页面位置不变,所以提交后不能整体刷新页面,因为刷新以后页面肯定在最上面,而评论一般都在最下面,所以要用到Ajax

整个过程用到了Django,Vue.js,reqwest,REST_framework,ajax

展示评论内容

展示评论内容可以直接用Django从数据库中取出数据,然后在view中渲染到前端,但这里我想用Vue.js,为了减少django的工作量,提高效率吧

// pinglun.js
let vue = new Vue({
    el : "#app",
    data : {
        pinglun : [
            {‘评论者‘:‘zhangsan‘,‘评论日期‘:‘2019-6-5‘,‘评论时间‘:‘17:47:23‘,‘评论内容‘:‘hahahha‘,‘对应文章_id‘:‘1‘},
            {‘评论者‘:‘zhangsan1‘,‘评论日期‘:‘2019-6-5‘,‘评论时间‘:‘17:48:23‘,‘评论内容‘:‘hahffahha‘,‘对应文章_id‘:‘1‘},
        ],
    },
})
<!--pinglun.html-->
<div id="app">
    <div class="alert alert-secondary" role="alert" id="pinglunlist">
        <div v-for="item in pinglun " >
            <h5>{{ item.评论者 }}</h5>
            <p>{{ item.评论内容 }}</p>
        </div>
    </div>
</div>

这样js中data的数据就可以渲染到html页面了,但我们需要从数据库中拿到数据,并且赋值给data中的pinglun,这里需要一个reqwest模块,需要下载

npm i reqwest

下载之后访问json文件里面的那个网址,下载压缩包,解压后里面有一个reqwest.js文件,要把这个文件引入,就和用Vue要引入Vue.main.js一样,reqwest可以从一个url请求数据,并且返回

// 这是官方api
reqwest({
    // 要请求的路径
    url: ‘path/to/html‘
    // 请求方式
  , method: ‘post‘
    // 请求时要携带的数据
  , data: { foo: ‘bar‘, baz: 100 }
    // 成功请求的回调函数
  , success: function (resp) {
      // reap中就包含请求来的数据
      qwery(‘#content‘).html(resp)
    }
})
reqwest({
    url: ‘path/to/html‘
  , method: ‘get‘
  , data: [ { name: ‘foo‘, value: ‘bar‘ }, { name: ‘baz‘, value: 100 } ]
  , success: function (resp) {
      qwery(‘#content‘).html(resp)
    }
})

应为需要有一个请求的url,所以还需要做一个api接口,这里有两种办法,一种是用Django提供的HttpResponse和json直接将序列化后的json数据渲染到页面,但这样只能渲染成json类型,并且存在文字编码的问题,还可以使用django-rest-framework框架,Django REST框架是一个功能强大且灵活的构建Web api工具包

使用 HttpResponse ,不推荐



# urls.py
path(‘api/json‘,views.injson),

# views.py
def injson(request):
    # 这里的info是手写的假数据,若使用这种方法可以从数据库中获取相应数据再用json.dumps序列化
    info = [{‘评论者‘:‘zhangsan‘,‘评论日期‘:‘2019-6-5‘,‘评论时间‘:‘17:47:23‘,‘评论内容‘:‘hahahha‘,‘对应文章_id‘:‘1‘},
            {‘评论者‘:‘zhangsan1‘,‘评论日期‘:‘2019-6-5‘,‘评论时间‘:‘17:48:23‘,‘评论内容‘:‘hahffahha‘,‘对应文章_id‘:‘1‘},]
    return HttpResponse(json.dumps(info))

使用REST框架

先要安装这个包以及依赖项

pip install djangorestframework
pip install markdown       # Markdown support for the browsable API.
pip install django-filter  # Filtering support

其次需要在setting.py中配置app

INSTALLED_APPS = [
    ‘django.contrib.admin‘,
    ‘django.contrib.auth‘,
    ‘django.contrib.contenttypes‘,
    ‘django.contrib.sessions‘,
    ‘django.contrib.messages‘,
    ‘django.contrib.staticfiles‘,
    ‘myblog‘,
    # 这个就是REST依赖项
    ‘rest_framework‘
]

然后就要写api了,先把评论的model放出来

class 评论(models.Model):
    评论者=models.CharField(max_length=20)
    评论日期=models.DateField(auto_now_add=True)
    评论时间=models.TimeField(auto_now_add=True)
    评论内容=models.TextField()
    对应文章=models.ForeignKey(‘myblog.文章内容‘,on_delete=models.CASCADE)

然后编写api.py

# api.py

# 引入model
from .models import 评论
# REST提供的序列化工具
from rest_framework import serializers
from rest_framework.response import Response
from rest_framework.decorators import api_view

Resonse

类似于HttpResponse,用来渲染文本内容,并根据内容决定返回给用户的数据类型

Response(data, status=None, template_name=None, headers=None, content_type=None)

# data:要渲染的数据,可以是python的基本数据类型
# status:状态码
# template_name:模板名称
# headers:头部信息
# content_type:内容类型的响应

因为Response只能渲染python基本数据类型,对于复杂的数据类型,需要serializers.ModelSerializer来序列化

# api.py

class PingLun(serializers.ModelSerializer):
    class Meta:
        depth = 1
        model = 评论
        fields = (‘评论者‘,‘评论日期‘,‘评论内容‘)

然后就可以写url对应的回调函数了,可以不使用api_view修饰器,但需要自己写一个判断来判断请求的类型

@api_view([‘GET‘])
def showdata(request):
    id = request.GET[‘id‘]
    print(id)
    datas=评论.objects.filter(对应文章_id=id)
    PingLunData = PingLun(datas,many=True)
    return Response({‘data‘:PingLunData.data})

这时候访问api就可以看到优雅的数据了,完了以后完善Vue,编写reqwest的内容

let vue = new Vue({
    el : "#app",
    data : {
        // 开始是一个空列表
        pinglun : [],
    },
    mounted(){
        console.log("卖个萌咋了!!!(>人<;)")
        this.getData()
    },
    computed : {

    },
    methods : {
        getData : function() {
            // 现在的this是window对象,等进入reqwest,this就是rewqest对象了,所以提前保存this
            let self = this
            // 只是为了获取当前文章的id
            let myurl = window.location.href
            let id = myurl.toString().split("/").pop()
          reqwest({
              url: ‘/blog/api/showpinglun/?format=json‘
              , method: ‘get‘
              , data: [{name: ‘id‘,value: id}]
              , success: function (data) {
                    self._data.pinglun = data.data
            }
        })
        },
    }
})

到目前,就可以使用Vue从数据库中获取数据并渲染到前端了,总结一下:

  1. 要用Vue渲染数据,数据就必须在data中,但我们又不能写死,必须从一个地方动态获取数据
  2. 这个地方就是api,django有一个模块REST专门用来建立api
  3. 要动态请求数据,需要用到一个框架 reqwest
  4. REST渲染数据用到了Resonse,但它只能渲染python基本数据,从Object.filter()得到的显然不是,因此还要序列化数据,这里用到了serializers
  5. 另外,还需要api_view这个装饰器判断请求类型

提交评论

思路:

  1. 使用POST请求
  2. 把表单内容交给api,api再保存到数据库

看着挺简单,但这里面有两个问题:

  1. Django要求所有POST请求进行CSRF验证,使用正常的表单我们可以添加{{csrf_token}},Django会自动在Cookies中添加csrf验证用的随机序列,用reqwest怎么办
  2. 一般情况下提交评论后评论会立刻显示在下面,怎么做

解决Ajax发送POST请求的CSRF问题

这里有两种思路

思路一:解决发现问题的人

这种思路简单粗暴,既然问题出在了csrf验证上,那就不让他进行验证就好了嘛,组织进行验证有两个简单的办法

使用装饰器

在要取消进行csrf验证的视图函数上添加修饰器@csrf_exempt

from django.views.decorators.csrf import csrf_exempt
@csrf_exempt
def demo(request):
    pass
赶尽杀绝法

第二种是狼人的做法,比较绝,直接从setting中删除csrf验证的依赖项

MIDDLEWARE = [
    ‘django.middleware.security.SecurityMiddleware‘,
    ‘django.contrib.sessions.middleware.SessionMiddleware‘,
    ‘django.middleware.common.CommonMiddleware‘,
    # 就是这个,删了就ok,但安全性嘛,就。。。。
    ‘django.middleware.csrf.CsrfViewMiddleware‘,
    ‘django.contrib.auth.middleware.AuthenticationMiddleware‘,
    ‘django.contrib.messages.middleware.MessageMiddleware‘,
    ‘django.middleware.clickjacking.XFrameOptionsMiddleware‘,
]

思路二:釜底抽薪

思路一实现简单,一劳永逸,看似不错,但取消csrf验证会让网站处于很危险的境地,建议不要这样用,第二种方法就要优雅很多,首先要知道Django是怎样防御CSRF攻击的,CSRF,跨站请求伪造攻击,是攻击者利用用户登录保存的cookies伪装成用户进行非发操作的攻击方式,比如攻击者在某网站留下了一个付款的链接www.xxxx.com/shop?money=500;to=hark(注意,这个链接已经设计了用户验证,只有正确登录后才能付款,没登录直接访问这个链接会被重定向到登录界面),一个受害者在访问这个钓鱼链接之前正好访问过付款的那个网站,并登录留下了自己的cookies,这时候她再去访问那个钓鱼链接,浏览器就会检查本地有没有对应的cookies文件,正好有,系统就认为是他本人在付款,这就是一次csrf攻击,csrf的特点是攻击者并没有拿到受害人的cookies,针对这个特点,django的处理办法是在cookies中增加一个csrf_token字段,内容为随机序列,同时表单提交时也把这个序列作为表单的一项同表单数据一起提交给后端做验证,如果表单中的序列与cookies中的序列不一样,就定义为csrf攻击,在Debug模式下会抛出403错误。

根据这个,我们只要在Ajax的请求头中加上cookies中的那个字段就可以了嘛,其实如果不懂csrf,直接在浏览器开发者工具里对比我们的Ajax请求头和正常的POST请求头就会发现我们少了X-CSRFToken这个字段,获取本站cookies中的csrftoken字段,添加到请求头中就可以。其实对比发现我们还缺了一项,不写会报500错误,Content-Type

setRequestHeader必须写在open之后
// js获取cookies依赖下面的库
<script src="https://cdn.jsdelivr.net/npm/[email protected]/src/js.cookie.min.js"></script>

// 获取cookies
let csrftoken = Cookies.get(‘csrftoken‘);

// 设置请求头
XHRObject.setRequestHeader("X-CSRFToken", csrftoken);

Ajax发送POST请求

<div id="app">
       <div class="alert alert-primary" role="alert">
            <p>评论<<</p>
             <hr />
           <div class="form-group">
                <label for="exampleFormControlInput1">评论者:</label>
                <input type="text" class="form-control" id="exampleFormControlInput1" placeholder="请输入你的姓名" name="评论者" maxlength="20" required="">
            </div>
            <div class="form-group">
                <label for="exampleFormControlTextarea1">有问题?不妨写下了...</label>
                <textarea class="form-control" name="评论内容" id="exampleFormControlTextarea1" rows="3"></textarea>
            </div>
        <hr>
           <button type="submit" name="评论提交"  οnclick="XMLDoc()"">提交评论</button>
    </div>
    function XMLDoc(){
        let XHRObject
        // 适配浏览器
        if(window.XMLHttpRequest){
            XHRObject = new XMLHttpRequest
        }else{
            XHRObject =new  ActiveXObject("Microsoft.XMLHTTP")
        }
        // 接收
        XHRObject.onreadystatechange = function () {
            if (XHRObject.status == 200 & XHRObject.readyState == 4) {
                }
        }

        // 获取文章id
        let url = window.location.href
        let id = url.toString().split("/").pop()
        // 获取csrftoken
        let csrftoken = Cookies.get(‘csrftoken‘);
        // 获取表单数据
        let name = document.getElementById(‘exampleFormControlInput1‘).value
        let neirong = document.getElementById(‘exampleFormControlTextarea1‘).value
        // 发送POST请求
        XHRObject.open("POST","/blog/api/postpinglun/?format=json",true)
        // 设置请求头
        XHRObject.setRequestHeader("X-CSRFToken", csrftoken);
        XHRObject.setRequestHeader("Content-Type", "application/x-www-form-urlencoded");
        // 发送请求,只接受一个字符串,键值用=连接,多个键值对用&连接
        XHRObject.send(‘name=‘+name+‘&neirong=‘+neirong+‘&id=‘+id.toString())
        document.getElementById(‘exampleFormControlInput1‘).value = ""
        document.getElementById(‘exampleFormControlTextarea1‘).value = ""
    }

api保存数据到数据库

@api_view([‘POST‘])
def postdata(request):
    # 获取Ajax传来的表单信息
    name = request.POST[‘name‘]
    neirong = request.POST[‘neirong‘]
    id = request.POST[‘id‘]
    # 保存到数据库
    obj=评论(
        评论者 = name,
        评论日期 = datetime.datetime.now().strftime(‘%Y-%m-%d‘),
        评论时间 = datetime.datetime.now().strftime(‘%H:%M:%S‘),
        评论内容 = neirong,
        对应文章_id = id
    )
    obj.save()

提交数据时更新下方评论列表

要在提交时更新,就要绑定两个单击事件,一个是Ajax的,用来保存数据,另一个是Vue的,用来更新数据,这里可以直接调用之前的getData函数

  <button type="submit" name="评论提交"  onclick="XMLDoc()" @click="getData()">提交评论</button>

原文:
http://blog.gqylpy.com/gqy/440

原文地址:https://www.cnblogs.com/mypath1/p/11407313.html

时间: 2024-08-03 20:31:22

Django,Ajax,Vue实现文章评论功能 𖇍的相关文章

文章详情页文章评论功能

一.文章评论功能实现流程 文章评论包含两种评论,根评论:对文章的评论:子评论:对评论的评论.两者的区别在于是否存在父评论. 实现流程:1.构建样式:2.提交根评论:3.显示根评论(分为render显示和Ajax显示):4.提交子评论:5.显示子评论(分为render显示和Ajax显示):6.评论树显示(博客园是楼层显示). 二.构建评论样式 1.article_detail.html: {# 文章点赞,清除浮动 #} <div class="clearfix"> <d

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

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

Vue系列之 =&gt; 评论功能(小知识点串联)

1 <!DOCTYPE html> 2 <html lang="en"> 3 4 <head> 5 <meta charset="UTF-8"> 6 <meta name="viewport" content="width=device-width, initial-scale=1.0"> 7 <meta http-equiv="X-UA-Compat

微信评论功能开启 将成净土还是地狱?

微信自发布以来,就像一个在优越环境中长大的孩童.前期自然是无忧无虑,不过随着时间的推移,需要学习.增添的东西就越来越多.尤其是自5.0版本以来,支付.游戏.表情商店.微商.小视频.生活服务等功能的不断加入,让微信逐渐"丰满"起来.由此,微信从一个轻量级应用开始向"连接一切"的庞然巨物发展. 但不可否认的是,多项功能的添加,带来的不仅仅是有利的一面,弊端也日渐凸显,比如微商的两面性就被用户所熟知.近日,微信正式测试公众号文章的评论功能.这究竟会让微信变成净土,还是地狱

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

内容回顾    1. BBS项目 CMS        1. 登录            1. form组件            2. auth模块            3. 验证码        2. 注册            1. form组件                1. 生成html代码                    直接for循环form_obj,就能够遍历所有字段                2. 验证                    1. 默认的那些验证

django高级之点赞、文章评论及上传文件

目录: 点赞 文章评论 上传文件 保留页面条件 一.点赞 1.所用技术: django model F查询 js应用:$(function () {}); 为文件加载完成执行ready() 方法.等同于on时间,多实例,使用. 定时器方法:setInterval(方法,间隔多长时间(毫秒)执行一次) var obj = setInterval(function () { if(xxx <= 0){ clearInterval(obj);  //结束执行 },100); ps.setTimeout

微信公众号文章增加评论功能

开通微信认证的公众号可进入微信发布后台,进行评论申请,在微信后台出现评论管理市即可进行评论.默认发布文章是没有评论功能的.另外公众号运营者可以选择精选评论,公众帐号文章只显示被运营者放入精选的评论. 目前公众号的开通评论功能还在内测阶段,只开放给以媒体类型申请的公众号,个人或企业暂时还没有.

博客的评论功能

今天呢,我们一起来新增一个详细页面下的简单评论功能,又是一个简单到我都不好意思说的东东....当然啦,万丈高楼平地起,我们就从简单的开始,以后慢慢添加呗. 还是按照以前的老步骤,models>views>urls>templates. 因为我们要多一个评论功能,所以我们得新建一张用来保存评论数据的表.所已在models添加如下东东: class BlogComment(models.Model):     user_name = models.CharField('评论者名字', max

Django第8章: 多级评论树

模拟实现流程 代码 // 传入的参数形式要求 comment_list = comment_list = [ {'id': 1, 'content': '1111', 'parent_id': None, 'children_contents':[]}, ... ] // 转换成嵌套结果列表 def transform_list(comment_list): comment_dict = {} for d in comment_list: id = d.get('id') comment_dic