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

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>

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/457557.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

回归分析什么时候取对数_冬蜜什么时候取,冬天取蜂蜜的方法

大家好&#xff0c;我现在分享的是&#xff0c;在冬天是在什么时候取蜜&#xff01;冬天在我们南方&#xff0c;取蜜时间是十一月到十二月的时候&#xff0c;只要温度达到15度以上&#xff0c;蜂蜜封盖了就可以取蜜了&#xff0c;并且在冬天我们只能取一次&#xff0c;最晚取蜜…

Opencv与dlib联合进行人脸关键点检测与识别

前言 依赖库&#xff1a;opencv 2.4.9 /dlib 19.0/libfacedetection 本篇不记录如何配置&#xff0c;重点在实现上。使用libfacedetection实现人脸区域检测&#xff0c;联合dlib标记人脸特征点&#xff0c;最后使用opencv的FaceRecognizer实现人脸识别。 准备工作 1、配置好Op…

Category 的一些事

来源&#xff1a;伯乐在线 - Tsui YuenHong 链接&#xff1a;http://ios.jobbole.com/90422/ 点击 → 申请加入伯乐在线专栏作者 新增实践部分&#xff1a;偏方 Hook 进某些方法来添加功能 Category – 简介 Category&#xff08;类别&#xff09;是 Objective-C 2.0 添加的新特…

python tfidf特征变换_机器学习的“万能模板” - 数据分析

最后是文本变量。很遗憾Titanic数据集中没有合适的文本变量。一般我们处理文本变量的方法是&#xff0c;合并所有的文本形成一个变量&#xff0c;然后调用Count Vectorizer或者TfidfVectorizer算法&#xff0c;将文本数据转换成数字。大部分情况下&#xff0c;TfidfVectorizer比…

python实现哈希表

# python 实现哈希表class HashTable:"""哈希函数的构造解决冲突"""def __init__(self, source):self.source sourceself._index []self._val []self.table []self._mod 13def Output(self):print(self._index)print(self._val)def _create…

商品综合评价排名

店内有很多产品&#xff0c;而且包含但不局限于以下指标&#xff1a;浏览量、访客数、平均停留时长、详情页跳出率、下单转化率、下单支付转化率、支付转化率、下单金额、下单商品件数、下单买家数、支付金额、支付商品件数、加购件数、访客平均价值、收藏人数、客单价、搜索支…

ionic资源网站

http://ionichina.com/topic/570b1f4ecd63e4247a7cfcf3 http://doc.ionicmaterialdesign.com/#intro http://ionicmaterial.com/demo/ 10大materialhttp://www.open-open.com/news/view/192f93e转载于:https://www.cnblogs.com/znsongshu/p/6079357.html

pytorch神经网络因素预测_实战:使用PyTorch构建神经网络进行房价预测

微信公号&#xff1a;ilulaoshi / 个人网站&#xff1a;lulaoshi.info本文将学习一下如何使用PyTorch创建一个前馈神经网络(或者叫做多层感知机&#xff0c;Multiple-Layer Perceptron&#xff0c;MLP)&#xff0c;文中会使用PyTorch提供的自动求导功能&#xff0c;训练一个神经…

SQL基本操作

SQL 操作 检索数据 SELECT 检索数据 -- 检索单个列 SELECT 列名 FROM table_name;-- 检索多个列 SELECT 列1, 列2 FROM table_name;-- 检索所有列 SELECT * FROM table_name;-- 检索不同的值 SELECT DISTINCT 列名 FROM table_name;限制检索结果 -- SQL Server / Access SE…

git 忽略 部分文件夹_git提交忽略某些文件或文件夹

记得第一次用 github 提交代码&#xff0c;node_modules 目录死活传不上去&#xff0c;哈哈哈&#xff0c;后来才知道在 .gitignore 文件里设置了忽略 node_modules 目录上传。是的&#xff0c; .gitignore 文件就是设置那些你不想用 git 一起上传的文件和文件夹。比如刚接触到…

Ajax实现原理详解

Ajax&#xff1a;Asynchronous javascript and xml&#xff0c;实现了客户端与服务器进行数据交流过程。使用技术的好处是&#xff1a;不用页面刷新&#xff0c;并且在等待页面传输数据的同时可以进行其他操作。 这就是异步调用的很好体现。首先得了解什么是异步和同步的概念。…

SpringJDBC解析3-回调函数(update为例)

PreparedStatementCallback作为一个接口&#xff0c;其中只有一个函数doInPrepatedStatement&#xff0c;这个函数是用于调用通用方法execute的时候无法处理的一些个性化处理方法&#xff0c;在update中的函数实现&#xff1a; protected int update(final PreparedStatementCr…

python上下文管理器

DAY 23. python上下文管理器 Python 的 with 语句支持通过上下文管理器所定义的运行时上下文这一概念。 此对象的实现使用了一对专门方法&#xff0c;允许用户自定义类来定义运行时上下文&#xff0c;在语句体被执行前进入该上下文&#xff0c;并在语句执行完毕时退出该上下文&…

勾股定理python思路_趣叮咚编程数学揭秘:为什么勾股定理a+b=c?

我们都知道&#xff1a;三角形3个外角之和360度可是谁知道为什么等于360度呢&#xff1f;其实利用编程制作动图演绎了解啦&#xff1a;那勾股定理abc又是为什么呢&#xff1f;还有很多有趣的数学公式都可以演绎&#xff1a;圆的面积公式、圆周长...通过动图演绎原来晦涩难懂的定…

System.InvalidOperationException : 不应有 Response xmlns=''。

xml如下&#xff1a; <?xml version"1.0" encoding"UTF-8"?> <Response version"2"><datacash_reference>4700203048783633</datacash_reference><information>Failed to identify the card scheme of the supp…

Navicat Premium连接SQL Server

Navicat Premium连接SQL Server 步骤&#xff1a; 激活SQL Server 服务配置SQL Server网络配置连接SQL Server 激活SQLServer服务 直接搜索 计算机管理 点 服务和应用程序&#xff0c; 点 SQL Server配置管理器&#xff0c; 双击第一个SQL Server服务 不出意外的话&#xf…

mysql 单标递归_MySql8 WITH RECURSIVE递归查询父子集的方法

背景开发过程中遇到类似评论的功能是&#xff0c;需要时用查询所有评论的子集。不同数据库中实现方式也不同&#xff0c;本文使用Mysql数据库&#xff0c;版本为8.0Oracle数据库中可使用START [Param] CONNECT BY PRIORMysql 中需要使用 WITH RECURSIVE需求找到name为张三的孩子…

processon完全装逼指南

一、引言 作为一名IT从业者&#xff0c;不仅要有扎实的知识储备&#xff0c;出色的业务能力&#xff0c;还需要具备一定的软实力。软实力体现在具体事务的处理能力&#xff0c;包括沟通&#xff0c;协作&#xff0c;团队领导&#xff0c;问题的解决方案等&#xff0c;这些能力在…

mysql在空闲8小时之后会断开连接(默认情况)

调试程序的过程发现&#xff0c;在mysql连接空闲一定时间&#xff08;默认8小时&#xff09;之后会断开连接&#xff0c;需要重新连接&#xff0c;也引发我对重连机制的思考。转载于:https://www.cnblogs.com/ppzbty/p/5707576.html

selector多路复用_多路复用器Selector

Unix系统有五种IO模型分别是阻塞IO(blocking IO)&#xff0c;非阻塞IO( non-blocking IO)&#xff0c;IO多路复用(IO multiplexing)&#xff0c;信号驱动(SIGIO/Signal IO)和异步IO(Asynchronous IO)。而IO多路复用通常有select&#xff0c;poll&#xff0c;epoll&#xff0c;k…