博客系統(二) 我的主頁,文章詳情頁

1、我的主頁

隨筆分類

需求:查詢當前站點每個分類的名稱以及對應的文章數css

完成這個需求,就能夠展現左側的分類html

它須要利用分組查詢,那麼必需要會基於雙下劃線的查詢。python

基於雙下劃線的查詢,簡單來說,就是用join。將多個表拼接成一張表,那麼就能夠單表操做了!mysql

表關係圖

圖中箭頭開始的英文字母表示關聯字段jquery

按照箭頭方向查詢,表示正向查詢,不然爲反向查詢linux

分解步驟:

先來查詢每個分類的名稱以及對應的文章數面試

看上面的關係圖,以Category表爲基礎表來查詢Article表對應的文章數,須要用到反向查詢。ajax

記住一個原則,正向查詢使用字段,反向查詢使用表名sql

修改views.py,導入相關表和聚合函數數據庫

from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from blog.models import Article,UserInfo,Blog,Category,Tag from django.db.models import Sum,Avg,Max,Min,Count # 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 homesite(request,username): """ 查詢 :param request: :param username: :return: """
    # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) ret = Category.objects.values("pk").annotate(c=Count("article__title")).values("title","c") print(ret) dict = {"blog":blog, "article_list":article_list, } return render(request,"homesite.html",dict)
View Code

解釋:

pk表示主鍵

上面這句sql表示以Category表id來分組,獲得分類名以及統計數

 

多添加幾篇文章,給另一個用戶也添加幾篇文章

 

訪問我的站點:http://127.0.0.1:8000/xiao/

查看Pycharm控制檯輸出:

<QuerySet [{'c': 1, 'title': 'python'}, {'c': 1, 'title': 'ajax'}, {'c': 2, 'title': 'django'}, {'c': 2, 'title': 'linux運維'}]>

上面獲得了全部文章的分類以及文章數。

 

再來查詢當前站點每個分類的名稱以及對應的文章數

思路:只須要對Category表進行篩選,過濾中當前站點用戶的分類

在homesite視圖函數中,已經有一個當前站點的blog對象。

在Category模型表中,有一個blog屬性,它和blog是一對多關係。那麼只須要blog=blog,就能夠了

修改視圖函數homesite的ret變量

ret = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values("title","c")

注意:等式左邊的blog表示Category模型表的blog屬性,實際上就是blog_id字段

等式右邊的是blog變量,它是一個model對象。那麼blog=blog,就能夠查詢出,當前站點的分類了!

 

刷新網頁,查看Pycharm控制檯輸出:

<QuerySet [{'title': 'python', 'c': 1}, {'title': 'ajax', 'c': 1}, {'title': 'django', 'c': 2}]

既然結果出來了,模板就能夠渲染了

 

修改homesite視圖函數,完整代碼以下:

from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from blog.models import Article,UserInfo,Blog,Category,Tag from django.db.models import Sum,Avg,Max,Min,Count # 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 homesite(request,username): """ 查詢 :param request: :param username: :return: """
    # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog print(blog,type(blog)) # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(cate_list) dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list } return render(request,"homesite.html",dict)
View Code

修改homesite.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        * { margin: 0; padding: 0; } .header { width: 100%; height: 59px; background-color: #369;
 } .header .title { line-height: 59px; color: white; font-weight: lighter; margin-left: 20px; font-size: 18px; } .left_region { margin-top: 10px; } .info { margin-top: 10px; color: darkgray; } h5 a { color: #105cb6;
            font-size: 14px; font-weight: bold; text-decoration: underline; } </style>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> Panel content </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> Panel content </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

            <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div>

                          <span class="small desc "> {{ article.desc }} </span>

                        </div>
                        <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                        </div>
                    </div>
                    <hr> {% endfor %} </div>

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


</body>
</html>
View Code

values_list返回的是一個元組,因此模板中,直接用cate.0就能夠取到分類名

 

刷新網頁,效果以下:

 

個人標籤

個人標籤和隨筆的查詢語句是相似的,換一個表名,就能夠了!

先在admin後臺爲不一樣的用戶,添加標籤

因爲admin後臺沒法直接將博客表和標籤表作對應關係,因此只能手動綁定關係。

使用navicat打開blog_article2tag表

注意:以實際狀況爲準

 

修改homesite視圖函數,查詢個人標籤

def homesite(request,username): """ 查詢 :param request: :param username: :return: """
    # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog print(blog,type(blog)) # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) #隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(cate_list) #個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(tag_list) dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list, "tag_list":tag_list, } return render(request,"homesite.html",dict)
View Code

刷新網頁,查看Pycharm控制檯

<QuerySet [('python全棧', 2)]>

 

修改homesite.html,開始渲染網頁

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        * { margin: 0; padding: 0; } .header { width: 100%; height: 59px; background-color: #369;
 } .header .title { line-height: 59px; color: white; font-weight: lighter; margin-left: 20px; font-size: 18px; } .left_region { margin-top: 10px; } .info { margin-top: 10px; color: darkgray; } h5 a { color: #105cb6;
            font-size: 14px; font-weight: bold; text-decoration: underline; } </style>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> {% for tag in tag_list %} <p><a href="">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> Panel content </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

            <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div>

                          <span class="small desc "> {{ article.desc }} </span>

                        </div>
                        <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                        </div>
                    </div>
                    <hr> {% endfor %} </div>

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


</body>
</html>
View Code

刷新網頁,效果以下:

注意:若是網頁數據沒有展現,請必定要查看數據庫是否有對應的記錄!

 

日期歸檔

查看Article表的create_time字段

注意:它的時間後面,有不少小數點。每一條是不同的,因此不能直接分組,不然沒有意義!

要實現這個功能,有3個小知識點:

  • 1.dateformat
  • 2.extra
  • 3.單表分組查詢

dateformat

DATE_FORMAT() 函數用於以不一樣的格式顯示日期/時間數據。

每一個數據庫都有日期/時間 處理的函數,在MySQL中,叫dateformat。SQLite中,叫strftime

舉例:

#截取年月日
mysql> select date_format("2018-07-11 06:39:07",'%Y-%m-%d') as date; +------------+
| date       |
+------------+
| 2018-07-11 |
+------------+
1 row in set (0.00 sec) #截取年月
mysql> select date_format("2018-07-11 06:39:07",'%Y-%m') as date; +---------+
| date    |
+---------+
| 2018-07 |
+---------+
1 row in set (0.00 sec)
View Code

 

extra

有些狀況下,Django的查詢語法難以表達複雜的where子句,對於這種狀況, Django 提供了extra()QuerySet修改機制 。它能在QuerySet生成的SQL從句中注入新子句,extra能夠指定一個或多個參數,例如select、where或tables。 這些參數都不是必須的,可是至少要使用一個。

語法:

extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)

select參數

select參數能夠在select從句中添加其餘字段信息,它應該是一個字典,存放着屬性名到 SQL 從句的映射。

舉例:

修改homesite視圖函數,增長几行代碼

def homesite(request,username): """ 查詢 :param request: :param username: :return: """
    # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog print(blog,type(blog)) # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) #隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(cate_list) #個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(tag_list) #測試日期
    test_date = Article.objects.filter(comment_count=0).extra(select={'y_m_date': "create_time > '2017-09-05'"}) print(test_date) for i in test_date: print(i.y_m_date) dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list, "tag_list":tag_list, } return render(request,"homesite.html",dict)
View Code

大概意思就是,查詢建立時間大於2017-09-05的記錄

刷新網頁,查看Pycharm控制檯輸出:

1
1
1

 

若是條件成立,返回1。不然返回0

須要注意的是:此時已經給Article表增長一個臨時字段y_m_date。它在內存中,每次使用extra查詢纔會存在!

 

單表分組查詢

查詢當前用戶的全部文章,根據日期歸檔

def homesite(request,username): """ 查詢 :param request: :param username: :return: """
    # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog print(blog,type(blog)) # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) #隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(cate_list) #個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") print(tag_list) #日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") print(date_list) dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list, "tag_list":tag_list, "date_list":date_list, } return render(request,"homesite.html",dict)
View Code

解釋:

SQLite的日期格式化使用strftime,它使用2個%號來區分。

user=user  等式左邊的user是Article模型表的user屬性,也就是user_id。等式右邊的user是UserInfo表的model對象!

 

刷新頁面,查看Pychram控制檯輸出:

<QuerySet [('2018/07', 4)]>

 

修改homesite.html,開始渲染網頁

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <style>
        * { margin: 0; padding: 0; } .header { width: 100%; height: 59px; background-color: #369;
 } .header .title { line-height: 59px; color: white; font-weight: lighter; margin-left: 20px; font-size: 18px; } .left_region { margin-top: 10px; } .info { margin-top: 10px; color: darkgray; } h5 a { color: #105cb6;
            font-size: 14px; font-weight: bold; text-decoration: underline; } </style>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> {% for tag in tag_list %} <p><a href="">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> {% for date in date_list %} <p><a href="">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

            <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div>

                          <span class="small desc "> {{ article.desc }} </span>

                        </div>
                        <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                        </div>
                    </div>
                    <hr> {% endfor %} </div>

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


</body>
</html>
View Code

刷新網頁,效果以下:

 

左側面板添加連接

接下來,須要點擊左邊的分類、標籤、歸檔,顯示相關的文章

訪問博客園左側的分類、標籤、歸檔,方法它有一個規律

標籤:

http://www.cnblogs.com/用戶名/tag/標籤名/

分類:

https://www.cnblogs.com/用戶名/category/分類id.html

歸檔:

https://www.cnblogs.com/用戶名/archive/年/月.html

 

修改urls.py,增長3個路徑。注意要導入re_path模塊

re_path('(?P<username>\w+)/category/(?P<params>.*)', views.homesite), re_path('(?P<username>\w+)/tag/(?P<params>.*)', views.homesite), re_path('(?P<username>\w+)/achrive/(?P<params>.*)', views.homesite),

仔細觀察我的站點網頁的佈局

發現,點擊不一樣的分類、標籤、歸檔。紅色區域和綠色區域始終不變,只有紫色區域在變更。變更區域取決於article_list變量!

那麼我的站點首頁、分類、標籤、歸檔這4種url能夠共用一個視圖函數homesite模板以及視圖函數。

從新修改urls.py,完整代碼以下:

from django.contrib import admin from django.urls import path,re_path from blog import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), path('logout/', views.logout), path('', views.index), # 跳轉
    re_path('(?P<username>\w+)/(?P<condition>category|tag|achrive)/(?P<params>.*)/$', views.homesite), # 我的站點
    re_path('(?P<username>\w+)/$', views.homesite), ]
View Code

那麼問題來了,訪問我的站點時,不須要額外的參數。

訪問分類/標籤/歸檔 這2個類別是,必需要2個額外的變量。分別是類別、類別參數。

homesite視圖函數,若是分別接收呢?答案是,使用**kwargs,它能夠接收可變的關鍵字參數,至少1個或者多個參數!

 

修改homesite.html,增長一個網頁圖標,不然待會測試時,會有2次請求。

若是網頁沒有圖標,每次會請求一次網絡請求,請求favicon.ico

在title標籤下面,增長一行

<link rel="shortcut icon" href="https://common.cnblogs.com/favicon.ico" type="image/x-icon" />

 

修改homesite視圖函數

def homesite(request,username,**kwargs): """ 查詢 :param request: :param username: :return: """
    print("kwargs", kwargs) # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog # 查詢當前用戶發佈的全部文章
    article_list=Article.objects.filter(user__username=username) #隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(cate_list)

    #個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(tag_list)

    #日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") # print(date_list)
 dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list, "tag_list":tag_list, "date_list":date_list, } return render(request,"homesite.html",dict)
View Code

訪問我的站點: http://127.0.0.1:8000/xiao/

Pycharm控制檯輸出:kwargs {}

 

訪問我的分類python: http://127.0.0.1:8000/xiao/category/python/

Pycharm控制檯輸出:kwargs {'params': 'python/', 'condition': 'category'}

 

訪問我的標籤: http://127.0.0.1:8000/xiao/tag/python全棧/

Pycharm控制檯輸出:kwargs {'params': 'python全棧/', 'condition': 'tag'}

 

訪問我的歸檔: http://127.0.0.1:8000/xiao/achrive/2018/07

Pycharm控制檯輸出:kwargs {'params': '2018/07', 'condition': 'achrive'}

注意:要帶上用戶名,不然出現404錯誤

 

那麼,只須要判斷kwargs變量,就能夠區分了!

修改homesite視圖函數

def homesite(request,username,**kwargs): """ 查詢 :param request: :param username: :return: """
    print("kwargs", kwargs) # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog # 查詢當前用戶發佈的全部文章
    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) #隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(cate_list)

    #個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(tag_list)

    #日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") # print(date_list)
 dict = {"blog":blog, "article_list":article_list, "cate_list":cate_list, "tag_list":tag_list, "date_list":date_list, "username":username, } return render(request,"homesite.html",dict)
View Code

修改homesite.html

<!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"/>

    <style>
        * { margin: 0; padding: 0; } .header { width: 100%; height: 59px; background-color: #369;
 } .header .title { line-height: 59px; color: white; font-weight: lighter; margin-left: 20px; font-size: 18px; } .left_region { margin-top: 10px; } .info { margin-top: 10px; color: darkgray; } h5 a { color: #105cb6;
            font-size: 14px; font-weight: bold; text-decoration: underline; } </style>
    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> {% for tag in tag_list %} <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

            <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div>

                          <span class="small desc "> {{ article.desc }} </span>

                        </div>
                        <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                        </div>
                    </div>
                    <hr> {% endfor %} </div>

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


</body>
</html>
View Code

訪問我的站點:http://127.0.0.1:8000/xiao/

效果以下:

 

主題切換

查看blog_blog表,有2條記錄

theme對應主題的css文件

在homesite.html中的style標籤訂義了一些樣式。如今須要分離出來!

每個用戶有本身的標題顏色,好比xiao用默認的藍色,zhang用綠色

在static中新建css目錄,在css中新建文件夾theme,新建3個css文件,其中common.css是公共樣式!

 

common.css

* { margin: 0; padding: 0; } .header { width: 100%; height: 59px; background-color: #369;
} .header .title { line-height: 59px; color: white; font-weight: lighter; margin-left: 20px; font-size: 18px; } .left_region { margin-top: 10px; } .info { margin-top: 10px; color: darkgray; } h5 a { color: #105cb6;
    font-size: 14px; font-weight: bold; text-decoration: underline; }
View Code

xiao.css

.header { width: 100%; height: 59px; background-color: #369;
}
View Code

zhang.css

.header { width: 100%; height: 59px; background-color: green; }
View Code

修改homesite.html,修改head部分,完整代碼以下:

<!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 }}">

    <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.css">
    <script src="/static/js/jquery.js"></script>
    <script src="/static/bootstrap/js/bootstrap.js"></script>
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> {% for tag in tag_list %} <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div>
                </div>
            </div>
        </div>
        <div class="col-md-9">

            <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div>

                          <span class="small desc "> {{ article.desc }} </span>

                        </div>
                        <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                        </div>
                    </div>
                    <hr> {% endfor %} </div>

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


</body>
</html>
View Code

使用谷歌瀏覽器登陸xiao的用戶,進入我的主頁

使用火狐瀏覽器登陸zhang的用戶

 

進入我的主頁,發現標題顏色沒有換過來

進入admin後臺,點擊users表,找到zhang用戶,發現它沒有綁定我的站點。

由於使用命令建立用戶時,blog_id字段,默認爲空!

手動綁定一下

再次刷新頁面,效果以下:

 

文章詳情

因爲文章詳情頁,功能繁多,必須專門作一個視圖才行。

修改urls.py,增長路徑article_detail

urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), path('logout/', views.logout), path('', views.index), #文章詳情
    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

因爲文章詳情頁的左測和標題部分是通用的,須要用到模板繼承

模板繼承

新建base.html,將homesite.html的代碼複製過來,刪除多餘的部分。增長block

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title> {#公共樣式#}
    <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="shortcut icon" href="https://common.cnblogs.com/favicon.ico" type="image/x-icon" />
</head>
<body>
<div class="header">
    <p class="title">{{ blog.title }}</p>
</div>


<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="left_region">
                <div class="panel panel-success">
                    <div class="panel-heading">
                        <h3 class="panel-title">隨筆分類</h3>
                    </div>
                    <div class="panel-body"> {% for cate in cate_list %} <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">
                        <h3 class="panel-title">個人標籤</h3>
                    </div>
                    <div class="panel-body"> {% for tag in tag_list %} <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>

                </div>
                <div class="panel panel-info">
                    <div class="panel-heading">
                        <h3 class="panel-title">日期歸檔</h3>
                    </div>
                    <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div>
                </div>
            </div>
        </div>
        <div class="col-md-9"> {% block content %} {% endblock %} </div>
    </div>
</div>


</body>
</html>
View Code

修改homesite.html

{% extends "base.html" %} {% block content %} <div class="article_list"> {% for article in article_list %} <div class="article_item clearfix">
                      <h5><a href="/{{ username }}/articles/{{ article.pk }}">{{ article.title }}</a></h5>
                      <div>

                          <span class="small desc "> {{ article.desc }} </span>

                      </div>
                      <div class="info small pull-right"> 發佈於 <span>{{ article.create_time|date:'Y-m-d H:i' }}</span>&nbsp;&nbsp; <span class="glyphicon glyphicon-comment"></span><a href="">評論({{ article.comment_count }})</a>&nbsp;&nbsp; <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a>
                      </div>
                 </div>
                    <hr> {% endfor %} </div> {% endblock %}
View Code

增長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 }} </div>
    </div> {% endblock %}
View Code

修改article_detail視圖函數

def article_detail(request,username,article_id): user = UserInfo.objects.filter(username=username).first() # 查詢當前站點對象
    blog = user.blog # 查詢指定id的文章
    article_obj=Article.objects.filter(pk=article_id).first() # 隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(cate_list)

    # 個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(tag_list)

    # 日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") # print(date_list)
 dict = {"blog": blog, "article_obj": article_obj, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list, "username": username, } return render(request,'article_detail.html',dict)
View Code

刷新網頁,點擊左側的一個分類,效果以下:

點擊右邊的一篇文章

關於內容部分,爲何是html標籤。這些暫時不處理,後面會講到如何處理!

查看article_detail和homesite 這2個視圖函數,有重複的代碼。在編程的過程當中,最好不要出現重複代碼,怎麼辦呢?使用函數封裝!

函數封裝

修改views.py,增長函數get_query_data。刪掉article_detail和homesite 這2個視圖函數中的重複代碼,完整代碼以下:

from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from blog.models import Article,UserInfo,Blog,Category,Tag from django.db.models import Sum,Avg,Max,Min,Count # 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 get_query_data(request,username): user = UserInfo.objects.filter(username=username).first() # 查詢當前站點對象
    blog = user.blog # 隨筆分類
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(cate_list)

    # 個人標籤
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(tag_list)

    # 日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") # print(date_list)
 dict = {"blog": blog, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list, "username": username, } return dict #返回字典


def homesite(request,username,**kwargs): """ 查詢 :param request: :param username: :return: """
    print("kwargs", kwargs) # 查詢當前站點的用戶對象
    user=UserInfo.objects.filter(username=username).first() if not user: return render(request,"not_found.html") # 查詢當前站點對象
    blog=user.blog # 查詢當前用戶發佈的全部文章
    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) dict = get_query_data(request,username)  #調用函數
    dict['article_list'] = article_list  # 增長一個key
    return render(request,"homesite.html",dict) def article_detail(request,username,article_id): content_text = get_query_data(request,username)  #調用函數
    #查詢指定id的文章
    article_obj = Article.objects.filter(pk=article_id).first() content_text['article_obj'] = article_obj  # 增長一個key

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

注意:get_query_data必需要在2個視圖函數的上面,不然沒法調用!

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

封裝函數,有一個侷限性,若是新增變量,須要增長字典key-value。因爲繼承模板時,變量是不會繼承的。因此引用的視圖函數,必須從新傳值才能夠渲染。那麼可不能夠,將模板和數據包裝成一個模板,做爲一個總體。其餘模板繼承時,就是一個已經渲染過的模板呢?

答案是有的,那就是inclusion_tag

 

包含標籤(Inclusion tags)

Django過濾器和標籤功能很強大,並且支持自定義標籤,非常方便;其中一種標籤是Inclusion tags,即包含標籤
包含標籤(Inclusion tags)經過渲染其餘的模板來展現內容,這類標籤的用途在於一些類似的內容的展現,而且返回的內容是渲染其餘模板獲得的內容。

自定義標籤必須在應用名目錄下建立templatetags目錄。注意:此目錄名必須叫這個名字,不可改變。

在templatetags目錄下,建立my_tags.py,這個文件名,是能夠隨便的

先來增長一個乘法的標籤

from django import template register=template.Library() @register.simple_tag def mul_tag(x,y): return x*y
View Code

修改article_detail.html,調用這個自定義標籤

{% extends "base.html" %} {% block content %} {% load my_tags %} <p>{% mul_tag 2 7 %}</p>
    <div class="article_info">
        <h4 class="text-center">{{ article_obj.title }}</h4>
        <div class="content"> {{ article_obj.content }} </div>
    </div> {% endblock %}
View Code

必須重啓django項目,不然模板沒法引用自定義標籤!

必須重啓django項目,不然模板沒法引用自定義標籤!

必須重啓django項目,不然模板沒法引用自定義標籤!

 

 

隨便訪問一篇文章,出現一個14,說明調用成功了

 

那麼這個my_tags,如何渲染左側的分類,標籤,歸檔呢?

新建標籤get_query_data,必須返回一個字典

將視圖函數中的相關代碼,複製過來便可。

from django import template register=template.Library() @register.simple_tag def mul_tag(x,y): return x*y from blog.models import Category,Tag,Article,UserInfo from django.db.models import Count,Avg,Max @register.inclusion_tag("left_region.html") def get_query_data(username): user = UserInfo.objects.filter(username=username).first() # 查詢當前站點對象
    blog = user.blog # 查詢當前站點每個分類的名稱以及對應的文章數
    cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # print(cate_list)

    # 查詢當前站點每個標籤的名稱以及對應的文章數
    tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c") # 日期歸檔
    date_list = Article.objects.filter(user=user).extra(select={"y_m_date": "strftime('%%Y/%%m',create_time)"}).values( "y_m_date").annotate(c=Count("title")).values_list("y_m_date", "c") # print(date_list)

    return {"blog":blog,"username":username,"cate_list":cate_list,"tag_list":tag_list,"date_list":date_list}
View Code

@register.inclusion_tag("left_region.html") 表示將返回結果渲染給left_region.html

 

若是在模板中有調用left_redig.html,那麼這個文件,就會渲染,是渲染後的html文件!

在templates中新建文件left_region.html

<div class="left_region">
    <div class="panel panel-success">
        <div class="panel-heading">
            <h3 class="panel-title">隨筆分類</h3>
        </div>
        <div class="panel-body"> {% for cate in cate_list %} <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p> {% endfor %} </div>
    </div>
    <div class="panel panel-warning">
        <div class="panel-heading">
            <h3 class="panel-title">個人標籤</h3>
        </div>
        <div class="panel-body"> {% for tag in tag_list %} <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p> {% endfor %} </div>
    </div>
    <div class="panel panel-info">
        <div class="panel-heading">
            <h3 class="panel-title">日期歸檔</h3>
        </div>
        <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/achrive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div>
    </div>
</div>
View Code

修改base.html,將<div class="col-md-3"></div> 中的內容部分,改成引用get_query_data標籤

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title> {#公共樣式#}
    <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="shortcut icon" href="https://common.cnblogs.com/favicon.ico" type="image/x-icon"/>
</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

此時刷新網頁,效果同上!

修改views.py中的視圖函數,刪除get_query_data!

刪除homesite和article_detail兩個視圖函數多餘的代碼

from django.shortcuts import render,HttpResponse,redirect from django.contrib import auth from blog.models import Article,UserInfo,Blog,Category,Tag from django.db.models import Sum,Avg,Max,Min,Count # 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): """ 查詢 :param request: :param username: :return: """
    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() return render(request,'article_detail.html',{"blog":blog,"username":username,'article_obj':article_obj})
View Code

注意:get_query_data標籤只是定義了左側的標籤!那麼homesite和article_detail兩個視圖函數,須要知道當前站點的博客標題。

因此須要專門定義個函數,來獲取博客標題!

 

修改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 }} </div>
    </div> {% endblock %}
View Code

從新訪問我的站點,隨便亂點,效果同上!

Inclusion tags的優勢:

1.不用在視圖函數中return字典

2.數據和樣式結合在一塊兒,返回一個渲染後的html

詳情頁顯示html代碼問題

訪問一篇博客詳情,好比:

http://127.0.0.1:8000/xiao/articles/5/

效果以下:

那麼django響應給瀏覽器的,真的是原來的html代碼嗎?

修改id爲5的文章記錄,修改content字段的數據,先備份一下,改爲一個h1標籤。

刷新網頁,效果以下:

打開瀏覽器控制檯-->network,查看此次請求的響應體

發現代碼被轉義了!那麼是誰轉義了呢?固然是....

注意:這不是瀏覽器的鍋,是django轉義的,這是它的安全策略作的。遇到html或者js代碼,會自動轉義!

那麼咱們不要django轉義呢?使用safe過濾器便可!

修改article_detail.html中的代碼

{{ article_obj.content|safe }}

從新刷新頁面,效果以下:

注意:這樣有一個安全隱患!

舉例:將內容修改成一段js代碼

從新刷新頁面,它會有一個提示框

注意:它只會彈一次。若是是下面這段代碼呢?

<script>for (var i = 0; i < 99999; i++) {alert("hello");}</script>

數據庫記錄以下:

刷新頁面試試?不用想了,你今天啥事不用幹,瘋狂的點擊吧!

那麼既要網頁安全,又須要網站展現真實的內容,怎麼辦呢?

答案就是:數據庫不存儲html代碼便可!存html和js代碼時,須要作特殊處理。

後面講到富文本編輯器,會講到。完美解決這個問題!

相關文章
相關標籤/搜索