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.pyclass PingLun(serializers.ModelSerializer):class Meta:depth = 1model = 评论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对象了,所以提前保存thislet self = this// 只是为了获取当前文章的idlet myurl = window.location.hreflet 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/js-cookie@2/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) {}}// 获取文章idlet url = window.location.hreflet id = url.toString().split("/").pop()// 获取csrftokenlet csrftoken = Cookies.get('csrftoken');// 获取表单数据let name = document.getElementById('exampleFormControlInput1').valuelet 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>

Django,Ajax,Vue实现文章评论功能相关推荐

  1. 文章详情页文章评论功能

    文章详情页文章评论功能 一.文章评论功能实现流程 文章评论包含两种评论,根评论:对文章的评论:子评论:对评论的评论.两者的区别在于是否存在父评论. 实现流程:1.构建样式:2.提交根评论:3.显示根评 ...

  2. easyui关闭dialog后刷新父页面_两种方法WordPress批量打开、关闭文章评论功能

    WordPress没有一键打开和关闭已发表文章评论的功能.只是是否允许在新发表的文章发表评论,或者自动关闭发布多少天前的文章的评论功能.由于一些需要,我们需要关闭最初在网站上打开的WordPress文 ...

  3. 织梦php实现评论,织梦文章评论功能的使用

    织梦是个很好的内容管理系统,其模型.频道.缓存功能都是十分的强大的,其文章评论也是很有特色的,因为织梦的文章评论是使用了ajax,这样即使是用的生成静态,也可以调取出最新的文章评论. 有的时候我们想单 ...

  4. Vue+SpringBoot实现评论功能

    目录 前言 难点 实现思路 数据表设计 数据传输格式设计 前端递归显示 删除评论 前言 评论系统相信大家并不陌生,在社交网络相关的软件中是一种常见的功能.然而对于初学者来说,实现一个完整的评论系统并不 ...

  5. Django博客功能实现—文章评论功能

    功能:在A网页提交一个评论Forms_B,提交之后自动刷新页面,能够显示刚刚的画面 思路:利用一个已经创建的表单,通过视图让其在网页中表现出来,填写玩信息之后提交,会提交到一个新的视图里面去做接受,接 ...

  6. 基于Python(Django )+VUE+MySQL实现多功能美颜 Web 应用【100010556】

    多功能美颜 Web 应用 第一部分引言 一.编写目的 编写本说明书的目的是为了准确阐述项目概要设计结构,本概要设计说明的作者是[巧倩美颜]项目组,本概要设计说明的确认者是[项目经理]负责人,本概要设计 ...

  7. 【vue】vue组件发表评论功能

    今天看了vue相关的视频,所以跟着做一个小demo把知识串联起来,内容很简单但是也算是学习道路上的一点进步. 1 思路分析 发表评论模块写入一个组件,提高复用性. 关键点: 子组件通过localSto ...

  8. 黑马博客——详细步骤(十二)项目功能的实现之文章评论和退出功能

    8.文章评论 1. 创建评论集合 2. 判断用户是否登录,如果用户登录,再允许用户提交评论表单 3. 在服务器端创建文章评论功能对应的路由 4. 在路由请求处理函数中接收客户端传递过来的评论信息 5. ...

  9. 纯jsp实现评论功能_基于云开发的小程序版本更新、评论功能改进、后台管理的实现...

    关于微信小程序更新问题实现 1)小程序的启动方式: 冷启动----小程序首次打开或销毁后再次被打开 热启动----小程序打开后,在一段时间内(目前:5分钟)再次被打开,此时会将后台的小程序切换到前台. ...

最新文章

  1. LeetCode中等题之简易银行系统
  2. Hibernate 异常 Unable to instantiate default tuplizer
  3. 【转】一台台式机电脑 是集成显卡,我现在想搞两个显示器,一台显示器看监控,一台显示器自己...
  4. Linux下vi和vim模式相互切换
  5. java listen_Java进阶-IO基础
  6. 前端请求接口post_前端如何优雅地模拟接口请求?(给你的代码加点小意外)
  7. 理解 OpenStack Swift (3):监控和一些影响性能的因素 [Monitoring and Performance]
  8. 软考信息系统项目管理师_体系介绍_证书作用价值_报考条件_考生分析---软考高级之信息系统项目管理师001
  9. Android编程之ActivityManager: Segmentation fault
  10. php安装oci8和pdo_oci扩展实现连接oracle数据库
  11. C# TextBox光标位置设置 滚动到最后一行 显示最后一行 自动跳转最后一行
  12. linux ubuntu 加密狗,ubuntu – 将usb加密狗连接到KVM VM
  13. NLP中文句子类型判别和分类实现
  14. 使用dkms将驱动加入内核模块
  15. 常用的统计抽样分布和正态总体的抽样分布
  16. 帕累托最优和纳什均衡例子
  17. 使用adb命令管理应用
  18. idea git操作
  19. java SE 7规范(又名JDK 7)
  20. 计算机的录像功能在哪里找,电脑录像功能在哪

热门文章

  1. PLSQL 安装+配置( Oracle数据库连接工具 )
  2. no typehandler found for property XXXX 解决
  3. docker学习4-docker安装mysql环境
  4. windows下安装和设置gradle
  5. 十五、详述 IntelliJ IDEA 插件的安装及使用方法
  6. Python全局变量和局部变量
  7. js setTimeout 使用方法
  8. Opencv与dlib联合进行人脸关键点检测与识别
  9. 关于C/C++中的“auto”关键字
  10. Hadoop的改进实验(中文分词词频统计及英文词频统计)(4/4)