博客系統(三) 點贊和踩滅,用戶評論

1、點贊和踩滅

樣式

先來作樣式,修改article_detail.html,增長div_digg的divcss

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>

{% endblock %}
View Code

在static-->css目錄下,建立文件article_detail.csshtml

#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url("/static/img/upup.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url("/static/img/downdown.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}
View Code

從博客園拷貝2個圖片到static-->img目錄下jquery

修改base.html,引入article_detail.cssgit

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="shortcut icon" href="https://common.cnblogs.com/favicon.ico" type="image/x-icon"/>
    {#公共樣式#}
    <link rel="stylesheet" href="/static/css/theme/common.css">
    {#我的站點主題樣式#}
    <link rel="stylesheet" href="/static/css/theme/{{ blog.theme }}">
    {#bootstrap#}
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
    {#文章詳情#}
    <link rel="stylesheet" href="/static/css/article_detail.css">

</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            {#加載自定義標籤模塊#}
            {% load my_tags %}
            {#調用get_query_data標籤,它返回left_region.html,是已經被渲染過的文件#}
            {% get_query_data username %}
        </div>
        <div class="col-md-9">

            {% block content %}

            {% endblock %}

        </div>
    </div>
</div>

</body>
</html>
View Code

點擊一篇文章:http://127.0.0.1:8000/xiao/articles/5/ajax

拉到最下面,右側效果以下:數據庫

 

綁定事件

推薦和反對有2個按鈕,要綁定2個事件嗎?答案是能夠,可是不推薦使用!爲何呢?django

由於會形成大量代碼重複!這2個按鈕須要發送的文章id和用戶id是同樣的,惟一不一樣的就是:一個是推薦,一個是反對。json

修改article_detail.html增長div,測試js代碼bootstrap

注意:在base.html中已經導入了jquery瀏覽器

hasClass() 方法檢查被選元素是否包含指定的 class。它返回True和False

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            alert(is_up);

        })
    </script>

{% endblock %}
View Code

刷新網頁,點擊文章右下角的推薦,提示true

點擊反對,提示false

 

發送ajax請求

數據分析

究竟是用get仍是post呢?有一個規範:查詢用get,更改用post

查看blog_articleupdown表,這個是點贊表。插入一條記錄,須要3個參數,分別是是否點贊、文章id、用戶id

注意:這個用戶id是當前登陸用戶,不是文章做者!

因爲在視圖函數中,有一個全局變量request.user。它是用戶登陸以後,纔有的!因此這個用戶id,不須要傳。

只須要傳2個值就能夠了,分別是是否點贊和文章id。

在article_detail.html中,已經有一個article_obj,它是一個model對象,那麼就能夠獲得文章id。

是否點贊,經過js代碼中的is_up變量,也能夠知道。

因此發送的數據,不須要使用標籤選擇器來獲取。直接使用便可!

操做流程

  1. 用戶點擊推薦或者反對,觸發點擊事件
  2. 發送ajax請求給服務器
  3. 服務器接收參數,生成一條點贊或者踩滅的記錄
  4. 服務器將返回結果響應給瀏覽器,瀏覽器中的ajax代碼的success中的data接收響應體
  5. ajax對響應的數據作判斷,操做DOM,顯示給用戶看!

服務器處理

修改urls.py,增長一個路徑digg

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('', views.index),
    #點贊或者踩滅
    path('digg/', views.digg),

    #文章詳情
    re_path('(?P<username>\w+)/articles/(?P<article_id>\d+)/$', views.article_detail),
    # 跳轉
    re_path('(?P<username>\w+)/(?P<condition>category|tag|achrive)/(?P<params>.*)/$', views.homesite),
    # 我的站點
    re_path('(?P<username>\w+)/$', views.homesite),
]
View Code

注意:digg要放到文章詳情的上面

修改article_detail.html

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

修改views.py,增長視圖函數digg

注意:導入2個模塊

import json
from django.http import JsonResponse

視圖函數以下:

from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth
from blog.models import Article,UserInfo,Blog,Category,Tag,ArticleUpDown
from django.db.models import Sum,Avg,Max,Min,Count
from django.db.models import F
import json
from django.http import JsonResponse

# Create your views here.
def login(request):

    if request.method=="POST":
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")
        # 用戶驗證成功,返回user對象,不然返回None
        user=auth.authenticate(username=user,password=pwd)
        if user:
            # 登陸,註冊session
            # 全局變量 request.user=當前登錄對象(session中)
            auth.login(request,user)
            return redirect("/index/")

    return render(request,"login.html")

def index(request):
    article_list=Article.objects.all()
    return render(request,"index.html",{"article_list":article_list})

def logout(request):  # 註銷
    auth.logout(request)
    return redirect("/index/")

def query_current_site(request,username):  # 查詢當前站點的博客標題
    # 查詢當前站點的用戶對象
    user = UserInfo.objects.filter(username=username).first()
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象
    blog = user.blog
    return blog

def homesite(request,username,**kwargs):  # 我的站點主頁
    print("kwargs", kwargs)

    blog = query_current_site(request,username)

    # 查詢當前用戶發佈的全部文章
    if not kwargs:
        article_list = Article.objects.filter(user__username=username)
    else:
        condition = kwargs.get("condition")
        params = kwargs.get("params")
        #判斷分類、隨筆、歸檔
        if condition == "category":
            article_list = Article.objects.filter(user__username=username).filter(category__title=params)
        elif condition == "tag":
            article_list = Article.objects.filter(user__username=username).filter(tags__title=params)
        else:
            year, month = params.split("/")
            article_list = Article.objects.filter(user__username=username).filter(create_time__year=year,
                                                                                  create_time__month=month)
    return render(request,"homesite.html",{"blog":blog,"username":username,"article_list":article_list})

def article_detail(request,username,article_id):
    blog = query_current_site(request,username)

    #查詢指定id的文章
    article_obj = Article.objects.filter(pk=article_id).first()
    user_id = UserInfo.objects.filter(username=username).first().nid

    return render(request,'article_detail.html',{"blog":blog,"username":username,'article_obj':article_obj,"user_id":user_id})

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
        else:
            #插入一條記錄
            new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

json處理問題

ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值

json支持7種數據格式,其中true和false是其中2種。那麼反序列化以後,會獲得一個布爾值。

爲何必定要反序列化呢?由於...create(...is_up=is_up) 等式右邊的值,非空。那麼ORM會認爲是True!

因此無論ajax傳過來的是true和falase,它都是字符串,那麼ORM執行時,始終都是True

JsonResponse

JsonResponse對象是HttpRespon的子類,它主要和父類的區別在於:

1.它的默認Content-Type 被設置爲: application/json

2.第一個參數,data應該是一個字典類型,若是不是字典,拋出 TypeError的異常

它返回json數據,那麼ajax接收時,不須要反序列化,能夠直接使用!

 

刷新網頁,點擊右側的推薦,查看瀏覽器控制檯

查看blog_articleupdown表記錄,發現多了一條記錄

查看Pycharm控制檯輸出:

<QueryDict: {'article_id': ['6'], 'csrfmiddlewaretoken': ['JgLyFpVgp92Rs8ppPCd2pm9jVj6z8bo9KSsMwKnakpB6CwTCT1K58v2JHLeR5ejN'], 'is_up': ['true']}>

 

判斷用戶以前的操做

當用戶第一次點擊推薦時,直接將數字加1。再次點擊時,提示您已經推薦過!再次點擊返回時,也提示您已經推薦過。

同理,當用戶對一篇點擊返回後。以後不管是點擊推薦仍是反對,都會提示您已經反對過!

不能夠取消推薦或者反對!

修改views.py,獲取上一次操做的記錄

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            #插入一條記錄
            new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

修改article_detail.html的js代碼

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                        } else {
                            if (data.handled) {  //判斷以前的操做記錄
                                $("#digg_tips").html("您已經推薦過!")
                            } else {
                                $("#digg_tips").html("您已經反對過!")
                            }
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

修改static-->css目錄下的article_detail.css,增長樣式

#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url("/static/img/upup.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url("/static/img/downdown.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}
.clear {
    clear: both;
}

#digg_tips{
    color: red;
}
View Code

重啓django項目,頁面強制刷新幾回!

再次點擊,提示已經點過了

修改article_detail.html的js代碼,增長動態效果,1秒後,清空紅色文字

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                        } else {
                            if (data.handled) {  //判斷以前的操做記錄
                                $("#digg_tips").html("您已經推薦過!")
                            } else {
                                $("#digg_tips").html("您已經反對過!")
                            }
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

效果以下:

 

更新文章表

blog_articleupdown表有一個聯合惟一索引,即便重複點擊,也不會增長記錄!

blog_article表有一個up_count和down_count字段,分別表示推薦和反對的計數。

那麼這2個字段,也須要同時更新。在原有數值的基礎上加1,須要使用F查詢!

導入F模塊,完整代碼以下:

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            #插入一條記錄
            new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
            if is_up: # 判斷爲推薦
                Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
            else: # 反對
                Article.objects.filter(pk=article_id).update(down_count=F("down_count")+1)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

清空blog_articleupdown表記錄

訪問網頁,從新點擊。再次刷新頁面,那麼值就會更新了!

 

網頁實時展現

上面已經實現了,點擊以後,更新數據庫。可是須要刷新網頁,纔會有效果。想要用戶能實時看到數字,須要進行DOM操做。

獲取網頁原有的值,進行加1。最後進行DOM操做,展現給用戶看!

修改article_detail.html的js代碼

注意:js是弱類型語言,獲取到值時,不能直接進行加法,須要強制轉換才行!

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this= $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val=_this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val)+1)
                        } else {
                            if (data.handled) {  //判斷以前的操做記錄
                                $("#digg_tips").html("您已經推薦過!")
                            } else {
                                $("#digg_tips").html("您已經反對過!")
                            }
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

清空blog_articleupdown表記錄

將blog_article表的相關字段設置爲0

訪問網頁,從新點擊,效果以下:

優化js代碼

將if判斷部分,改爲三元運算

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this = $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val = _this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val) + 1)
                        } else {
                            // 重複提交
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

 

事務

是指做爲單個邏輯工做單元執行的一系列操做,要麼徹底地執行,要麼徹底地不執行。 事務處理能夠確保除非事務性單元內的全部操做都成功完成,不然不會永久更新面向數據的資源。

在上面的例子,點贊時,須要更新2個表。一個是blog_articleupdown表,一個是blog_article表。

若是有一個表沒有更新,那麼就會產生髒數據!爲了不這個問題,須要使用事務!

舉例:模擬異常狀況

修改digg視圖函數,模擬異常

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            #插入一條記錄
            new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
            ask  # 這一行故意出錯
            if is_up: # 判斷爲推薦
                Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
            else: # 反對
                Article.objects.filter(pk=article_id).update(down_count=F("down_count")+1)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

清空blog_articleupdown表,將blog_article表的up_count和down_count字段設置爲0

刷新頁面,從新點擊,打開瀏覽器工具-->network

出行了500錯誤

 查看blog_articleupdown表,多了一條記錄

 

查看blog_article表,對應文章的up_count字段,發現仍是爲0

 

使用事務

修改digg視圖函數,導入模塊transaction。

使用語法很簡單,將相關原子操做的代碼直接tab一下,就能夠了

完整代碼以下:

from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth
from blog.models import Article,UserInfo,Blog,Category,Tag,ArticleUpDown
from django.db.models import Sum,Avg,Max,Min,Count
from django.db.models import F
import json
from django.http import JsonResponse
from django.db import transaction

# Create your views here.
def login(request):

    if request.method=="POST":
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")
        # 用戶驗證成功,返回user對象,不然返回None
        user=auth.authenticate(username=user,password=pwd)
        if user:
            # 登陸,註冊session
            # 全局變量 request.user=當前登錄對象(session中)
            auth.login(request,user)
            return redirect("/index/")

    return render(request,"login.html")

def index(request):
    article_list=Article.objects.all()
    return render(request,"index.html",{"article_list":article_list})

def logout(request):  # 註銷
    auth.logout(request)
    return redirect("/index/")

def query_current_site(request,username):  # 查詢當前站點的博客標題
    # 查詢當前站點的用戶對象
    user = UserInfo.objects.filter(username=username).first()
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象
    blog = user.blog
    return blog

def homesite(request,username,**kwargs):  # 我的站點主頁
    print("kwargs", kwargs)

    blog = query_current_site(request,username)

    # 查詢當前用戶發佈的全部文章
    if not kwargs:
        article_list = Article.objects.filter(user__username=username)
    else:
        condition = kwargs.get("condition")
        params = kwargs.get("params")
        #判斷分類、隨筆、歸檔
        if condition == "category":
            article_list = Article.objects.filter(user__username=username).filter(category__title=params)
        elif condition == "tag":
            article_list = Article.objects.filter(user__username=username).filter(tags__title=params)
        else:
            year, month = params.split("/")
            article_list = Article.objects.filter(user__username=username).filter(create_time__year=year,
                                                                                  create_time__month=month)
    return render(request,"homesite.html",{"blog":blog,"username":username,"article_list":article_list})

def article_detail(request,username,article_id):
    blog = query_current_site(request,username)

    #查詢指定id的文章
    article_obj = Article.objects.filter(pk=article_id).first()
    user_id = UserInfo.objects.filter(username=username).first().nid

    return render(request,'article_detail.html',{"blog":blog,"username":username,'article_obj':article_obj,"user_id":user_id})

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            with transaction.atomic():
                #插入一條記錄
                new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
                ask  # 模擬異常
                if is_up: # 判斷爲推薦
                    Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
                else: # 反對
                    Article.objects.filter(pk=article_id).update(down_count=F("down_count")+1)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

清空blog_articleupdown表

刷新頁面,從新點擊,再一次返回500錯誤

查看blog_articleupdown表,發現並沒增長一條記錄。

 

這樣就比較合理了!刪除異常代碼

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            with transaction.atomic():
                #插入一條記錄
                new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
                if is_up: # 判斷爲推薦
                    Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
                else: # 反對
                    Article.objects.filter(pk=article_id).update(down_count=F("down_count")+1)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")
View Code

刷新頁面,從新點擊

查看blog_articleupdown表,發現增長了一條記錄。

查看blog_article表,對應文章的up_count字段,發現爲1了!

事務用起來很簡單,是由於django把複雜的邏輯給封裝好了!
有時間的小夥伴,還能夠加一個需求,本身不能給本身點贊!

 

2、用戶評論

評論樣式

先寫html的樣式代碼

修改article_detail.html

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
    <div class="clearfix"></div>

        <div class="comment">
            <p>評論列表</p>
            <ul class="comment_list list-group">
                {% for comment in comment_list %}
                <li class="list-group-item">
                   <div>
                       <a href="">#{{ forloop.counter }}樓</a>&nbsp;&nbsp;
                       <span class="small">{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                       <a href="">{{ comment.user.username }}</a>
                       <a href="" class="pull-right"><span>回覆</span></a>

                   </div>
                   <div>
                       <p>{{ comment.content }}</p>
                   </div>
                </li>
                {% endfor %}

            </ul>
            <p>發表評論</p>
            <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value="{{ request.user.username }}"></p>
            <div>
                <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            </div>
            <input type="button" value="submit" class="btn btn-default comment_btn">
        </div>

    </div>
    {% csrf_token %}
    <script>
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this = $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val = _this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val) + 1)
                        } else {
                            // 重複提交
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })
    </script>

{% endblock %}
View Code

修改css目錄下的article_detail.css

注意放一個gif圖片到img目錄下

/*推薦和反對*/
#div_digg {
    float: right;
    margin-bottom: 10px;
    margin-right: 30px;
    font-size: 12px;
    width: 125px;
    text-align: center;
    margin-top: 10px;
}

.diggit {
    float: left;
    width: 46px;
    height: 52px;
    background: url("/static/img/upup.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}

.buryit {
    float: right;
    margin-left: 20px;
    width: 46px;
    height: 52px;
    background: url("/static/img/downdown.gif") no-repeat;
    text-align: center;
    cursor: pointer;
    margin-top: 2px;
    padding-top: 5px;
}
.clear {
    clear: both;
}

#digg_tips{
    color: red;
}

/*評論*/
 input.author{
    background-image: url("/static/img/icon_form.gif");
    background-repeat: no-repeat;
    border: 1px solid #ccc;
    padding: 4px 4px 4px 30px;
    width: 300px;
    font-size: 13px;
}

input.author {
    background-position: 3px -3px;
}
View Code

刷新網頁,拉到最下面,效果以下:

評論步驟

  • 提交根評論請求
  • 顯示根評論
  1. render
  2. Ajax顯示
  • 提交子評論
  • 顯示子評論
  • 評論樹

 

發送ajax請求

查看評論表模型

class Comment(models.Model):
    """

    評論表

    """
    nid = models.AutoField(primary_key=True)
    article = models.ForeignKey(verbose_name='評論文章', to='Article', to_field='nid', on_delete=models.CASCADE)
    user = models.ForeignKey(verbose_name='評論者', to='UserInfo', to_field='nid', on_delete=models.CASCADE)
    content = models.CharField(verbose_name='評論內容', max_length=255)
    create_time = models.DateTimeField(verbose_name='建立時間', auto_now_add=True)
    parent_comment = models.ForeignKey(verbose_name="父級評論id", to='Comment',null=True, on_delete=models.CASCADE)
View Code

它有6個字段,其中nid、user、parent_comment、create_time是可選的。

user 在視圖函數中,能夠直接獲取,不須要ajax傳此參數。

parent_comment字段的值爲空,表示這是一條根評論。不然爲一條子評論!

那麼ajax若是傳一個空值,表示爲根評論,不然爲子評論。

create_time字段有一個屬性:auto_now_add=True。

字段在實例第一次保存的時候會保存當前時間,無論你在這裏是否對其賦值。可是以後的save()是能夠手動賦值的。

也就是新實例化一個model,想手動存其餘時間,就須要對該實例save()以後賦值而後再save()

根評論

修改article_detail.html的js代碼,只須要發送3個參數便可。分別是content,atricle_id,parent_comment

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
        <div class="clearfix"></div>

        <div class="comment">
            <p>評論列表</p>
            <ul class="comment_list list-group">
                {% for comment in comment_list %}
                    <li class="list-group-item">
                        <div>
                            <a href="">#{{ forloop.counter }}樓</a>&nbsp;&nbsp;
                            <span class="small">{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                            <a href="">{{ comment.user.username }}</a>
                            <a href="" class="pull-right"><span>回覆</span></a>

                        </div>
                        <div>
                            <p>{{ comment.content }}</p>
                        </div>
                    </li>
                {% endfor %}

            </ul>
            <p>發表評論</p>
            <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                         value="{{ request.user.username }}"></p>
            <div>
                <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            </div>
            <input type="button" value="submit" class="btn btn-default comment_btn">
        </div>

    </div>
    {% csrf_token %}
    <script>
        // 點贊和踩滅
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this = $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val = _this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val) + 1)
                        } else {
                            // 重複提交
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })

        // 提交評論
        $(".comment_btn").click(function () {
            {#評論內容#}
            var content = $("#comment_content").val();
            {#默認爲空#}
            var pid = "";
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    content: content,
                    article_id: "{{ article_obj.pk }}",
                    pid: pid,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                },
                success: function (data) {
                    console.log(data);
                    // 清空輸入框的內容
                    $("#comment_content").val("")
                }
            })

        })
    </script>

{% endblock %}
View Code

修改urls.py,增長路徑comment

urlpatterns = [
    path('admin/', admin.site.urls),
    path('login/', views.login),
    path('index/', views.index),
    path('logout/', views.logout),
    path('', views.index),
    #點贊或者踩滅
    path('digg/', views.digg),
    # 評論
    path('comment/', views.comment),

    #文章詳情
    re_path('(?P<username>\w+)/articles/(?P<article_id>\d+)/$', views.article_detail),
    # 跳轉
    re_path('(?P<username>\w+)/(?P<condition>category|tag|achrive)/(?P<params>.*)/$', views.homesite),
    # 我的站點
    re_path('(?P<username>\w+)/$', views.homesite),
]
View Code

修改views.py,增長視圖函數comment,完整代碼以下:

from django.shortcuts import render,HttpResponse,redirect
from django.contrib import auth
from blog.models import Article,UserInfo,Blog,Category,Tag,ArticleUpDown,Comment
from django.db.models import Sum,Avg,Max,Min,Count
from django.db.models import F
import json
from django.http import JsonResponse
from django.db import transaction

# Create your views here.
def login(request):

    if request.method=="POST":
        user=request.POST.get("user")
        pwd=request.POST.get("pwd")
        # 用戶驗證成功,返回user對象,不然返回None
        user=auth.authenticate(username=user,password=pwd)
        if user:
            # 登陸,註冊session
            # 全局變量 request.user=當前登錄對象(session中)
            auth.login(request,user)
            return redirect("/index/")

    return render(request,"login.html")

def index(request):
    article_list=Article.objects.all()
    return render(request,"index.html",{"article_list":article_list})

def logout(request):  # 註銷
    auth.logout(request)
    return redirect("/index/")

def query_current_site(request,username):  # 查詢當前站點的博客標題
    # 查詢當前站點的用戶對象
    user = UserInfo.objects.filter(username=username).first()
    if not user:
        return render(request, "not_found.html")
    # 查詢當前站點對象
    blog = user.blog
    return blog

def homesite(request,username,**kwargs):  # 我的站點主頁
    print("kwargs", kwargs)

    blog = query_current_site(request,username)

    # 查詢當前用戶發佈的全部文章
    if not kwargs:
        article_list = Article.objects.filter(user__username=username)
    else:
        condition = kwargs.get("condition")
        params = kwargs.get("params")
        #判斷分類、隨筆、歸檔
        if condition == "category":
            article_list = Article.objects.filter(user__username=username).filter(category__title=params)
        elif condition == "tag":
            article_list = Article.objects.filter(user__username=username).filter(tags__title=params)
        else:
            year, month = params.split("/")
            article_list = Article.objects.filter(user__username=username).filter(create_time__year=year,
                                                                                  create_time__month=month)
    return render(request,"homesite.html",{"blog":blog,"username":username,"article_list":article_list})

def article_detail(request,username,article_id):
    blog = query_current_site(request,username)

    #查詢指定id的文章
    article_obj = Article.objects.filter(pk=article_id).first()
    user_id = UserInfo.objects.filter(username=username).first().nid

    return render(request,'article_detail.html',{"blog":blog,"username":username,'article_obj':article_obj,"user_id":user_id})

def digg(request):
    print(request.POST)
    if request.method == "POST":
        #ajax發送的過來的true和false是字符串,使用json反序列化獲得布爾值
        is_up = json.loads(request.POST.get("is_up"))
        article_id = request.POST.get("article_id")
        user_id = request.user.pk

        response = {"state": True, "msg": None}  # 初始狀態
        #判斷當前登陸用戶是否對這篇文章作過點贊或者踩滅操做
        obj = ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if obj:
            response["state"] = False  # 更改狀態
            response["handled"] = obj.is_up  # 獲取以前的操做,返回true或者false
            print(obj.is_up)
        else:
            with transaction.atomic():
                #插入一條記錄
                new_obj = ArticleUpDown.objects.create(user_id=user_id, article_id=article_id, is_up=is_up)
                if is_up: # 判斷爲推薦
                    Article.objects.filter(pk=article_id).update(up_count=F("up_count")+1)
                else: # 反對
                    Article.objects.filter(pk=article_id).update(down_count=F("down_count")+1)

        return JsonResponse(response)

    else:
        return HttpResponse("非法請求")

def comment(request):
    print(request.POST)
    if request.method == "POST":
        # 獲取數據
        user_id = request.user.pk
        article_id = request.POST.get("article_id")
        content = request.POST.get("content")
        pid = request.POST.get("pid")
        # 生成評論對象
        with transaction.atomic():  # 增長事務
            # 評論表增長一條記錄
            comment = Comment.objects.create(user_id=user_id, article_id=article_id, content=content, parent_comment_id=pid)
            # 當前文章的評論數加1
            Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
    
        response = {"state": False}  # 初始狀態
        
        if comment.user_id:  # 判斷返回值
            response = {"state": True}
        
        return JsonResponse(response)  # 返回json對象
    
    else:
        return HttpResponse("非法請求")
View Code

 

刷新網頁,發表一條評論

 查看錶blog_comment,多了一條記錄

查看blog_article表,對應的comment_count值,數值加1了。

 

 

渲染評論

修改article_detail視圖函數,將評論列表傳給模板

def article_detail(request,username,article_id):
    blog = query_current_site(request,username)

    #查詢指定id的文章
    article_obj = Article.objects.filter(pk=article_id).first()
    user_id = UserInfo.objects.filter(username=username).first().nid

    comment_list = Comment.objects.filter(article_id=article_id)
    dict = {"blog":blog,
            "username":username,
            'article_obj':article_obj,
            "user_id":user_id,
            "comment_list":comment_list,
            }

    return render(request,'article_detail.html',dict)
View Code

修改article_detail.html,使用for循環,遍歷列表

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
        <div class="clearfix"></div>

        <div class="comment">
            <p>評論列表</p>
            <ul class="comment_list list-group">
                {% for comment in comment_list %}
                    <li class="list-group-item">
                        <div>
                            <a href="">#{{ forloop.counter }}樓</a>&nbsp;&nbsp;
                            <span class="small">{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                            <a href="">{{ comment.user.username }}</a>
                            <a href="" class="pull-right"><span>回覆</span></a>

                        </div>
                        <div>
                            <p>{{ comment.content }}</p>
                        </div>
                    </li>
                {% endfor %}

            </ul>
            <p>發表評論</p>
            <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                         value="{{ request.user.username }}"></p>
            <div>
                <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            </div>
            <input type="button" value="submit" class="btn btn-default comment_btn">
        </div>

    </div>
    {% csrf_token %}
    <script>
        // 點贊和踩滅
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this = $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val = _this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val) + 1)
                        } else {
                            // 重複提交
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })

        // 提交評論
        $(".comment_btn").click(function () {
            {#評論內容#}
            var content = $("#comment_content").val();
            {#默認爲空#}
            var pid = "";
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    content: content,
                    article_id: "{{ article_obj.pk }}",
                    pid: pid,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                },
                success: function (data) {
                    console.log(data);
                    // 清空輸入框的內容
                    $("#comment_content").val("")
                }
            })

        })
    </script>

{% endblock %}
View Code

刷新網頁,效果以下:

 

評論實時展現

上面提交評論後,網頁不能當即看到,須要刷新以後,才能看到。這樣體驗很差!

查看博客園的評論,提交以後,會當即看到評論。此時不會顯示樓層,只會顯示評論內容!

那麼只須要提交成功以後,操做DOM,在評論列表中,追加一段li標籤,展現一下,就能夠了!

數據獲取問題

那麼內容從何而來呢?

1.直接從html中獲取相關數據

2.讓服務器返回相關數據,從響應體中取數據。

針對這2種方式,咱們選擇第2種!

爲何不選擇第一種呢?由於第一種是原始輸入框中的值,那麼存儲到數據後以後。就不必定仍是輸入框的值!

服務器存儲到數據庫以前,會將提交的數據,作一次處理!

咱們想要的效果,就是不管是DOM操做,追加一段html代碼。仍是刷新網頁,加載評論。這2種方式,評論內容是一摸同樣的!

因此,咱們必須選擇第二種方案,讓服務器返回存儲的值給ajax,ajax操做DOM,最加一段html代碼,給用戶展現!

 

數據展現

修改comment視圖函數,返回3個變量給ajax

def comment(request):
    print(request.POST)
    if request.method == "POST":
        # 獲取數據
        user_id = request.user.pk
        article_id = request.POST.get("article_id")
        content = request.POST.get("content")
        pid = request.POST.get("pid")
        # 生成評論對象
        with transaction.atomic():  # 增長事務
            # 評論表增長一條記錄
            comment = Comment.objects.create(user_id=user_id, article_id=article_id, content=content, parent_comment_id=pid)
            # 當前文章的評論數加1
            Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)

        response = {"state": False}  # 初始狀態

        if comment.user_id:  # 判斷返回值
            response = {"state": True}
        
        #響應體增長3個變量
        response["timer"] = comment.create_time.strftime("%Y-%m-%d %X")
        response["content"] = comment.content
        response["user"] = request.user.username
        
        return JsonResponse(response)  # 返回json對象

    else:
        return HttpResponse("非法請求")
View Code

修改article_detail.html中的js代碼,使用append最加一段li標籤

{% extends "base.html" %}

{% block content %}
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content">
            {{ article_obj.content|safe }}
        </div>
        <div id="div_digg">
            <div class="diggit action">
                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
            </div>
            <div class="buryit action">
                <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
            </div>
            <div class="clear"></div>
            <div class="diggword" id="digg_tips">
            </div>
        </div>
        <div class="clearfix"></div>

        <div class="comment">
            <p>評論列表</p>
            <ul class="comment_list list-group">
                {% for comment in comment_list %}
                    <li class="list-group-item">
                        <div>
                            <a href="">#{{ forloop.counter }}樓</a>&nbsp;&nbsp;
                            <span class="small">{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                            <a href="">{{ comment.user.username }}</a>
                            <a href="" class="pull-right"><span>回覆</span></a>

                        </div>
                        <div>
                            <p>{{ comment.content }}</p>
                        </div>
                    </li>
                {% endfor %}

            </ul>
            <p>發表評論</p>
            <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                         value="{{ request.user.username }}"></p>
            <div>
                <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            </div>
            <input type="button" value="submit" class="btn btn-default comment_btn">
        </div>

    </div>
    {% csrf_token %}
    <script>
        // 點贊和踩滅
        $(".action").click(function () {
            {#hasClass() 方法檢查被選元素是否包含指定的 class#}
            var is_up = $(this).hasClass("diggit");
            {#獲取提示的span標籤#}
            var _this = $(this).children("span");
            {#判斷是否登陸#}
            if ("{{ request.user.username }}") {
                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        is_up: is_up,
                        article_id: "{{ article_obj.pk }}",
                        csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                    },
                    success: function (data) {
                        console.log(data);
                        console.log(typeof data);
                        if (data.state) {
                            //提交成功
                            var val = _this.text();  //獲取text值
                            //在原有的基礎上加1。注意:必定要進行類型轉換
                            _this.text(parseInt(val) + 1)
                        } else {
                            // 重複提交
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);
                            setTimeout(function () {
                                $("#digg_tips").html("")  //清空提示文字
                            }, 1000)
                        }

                    }
                })
            } else {
                location.href = "/login/";
            }

        })

        // 提交評論
        $(".comment_btn").click(function () {
            {#評論內容#}
            var content = $("#comment_content").val();
            {#默認爲空#}
            var pid = "";
            $.ajax({
                url: "/comment/",
                type: "post",
                data: {
                    content: content,
                    article_id: "{{ article_obj.pk }}",
                    pid: pid,
                    csrfmiddlewaretoken: $("[name='csrfmiddlewaretoken']").val()
                },
                success: function (data) {
                    console.log(data);
                    {#獲取3個值#}
                    var comment_time = data.timer;
                    var comment_content = data.content;
                    var comment_user = data.user;
                    {#組織li標籤#}
                    var $li = ` <li class="list-group-item">
                                       <div>
                                           <span class="small">${comment_time}</span>&nbsp;&nbsp;
                                           <a href="">${comment_user}</a>
                                       </div>
                                       <div>
                                           <p>${comment_content}</p>
                                       </div>
                                    </li>`;
                    {#追加到評論列表中#}
                    $(".comment_list").append($li);
                    // 清空輸入框的內容
                    $("#comment_content").val("")
                }
            })

        })
    </script>

{% endblock %}
View Code

刷新網頁,從新評論,效果以下:

評論能夠實時展現了

刷新網頁,效果以下:

顯示出樓層

相關文章
相關標籤/搜索