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.pswp.cn/news/457557.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/457557.shtml
英文地址,請注明出處:http://en.pswp.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…