1、我的主頁
隨筆分類
需求:查詢當前站點每個分類的名稱以及對應的文章數css
完成這個需求,就能夠展現左側的分類html
它須要利用分組查詢,那麼必需要會基於雙下劃線的查詢。python
基於雙下劃線的查詢,簡單來說,就是用join。將多個表拼接成一張表,那麼就能夠單表操做了!mysql
表關係圖
圖中箭頭開始的英文字母表示關聯字段jquery
按照箭頭方向查詢,表示正向查詢,不然爲反向查詢linux
分解步驟:
先來查詢每個分類的名稱以及對應的文章數面試
看上面的關係圖,以Category表爲基礎表來查詢Article表對應的文章數,須要用到反向查詢。ajax
記住一個原則,正向查詢使用字段,反向查詢使用表名sql
修改views.py,導入相關表和聚合函數數據庫
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
解釋:
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視圖函數,完整代碼以下:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
修改homesite.html
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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> <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> </div> </div> </div> </body> </html>
values_list返回的是一個元組,因此模板中,直接用cate.0就能夠取到分類名
刷新網頁,效果以下:
個人標籤
個人標籤和隨筆的查詢語句是相似的,換一個表名,就能夠了!
先在admin後臺爲不一樣的用戶,添加標籤
因爲admin後臺沒法直接將博客表和標籤表作對應關係,因此只能手動綁定關係。
使用navicat打開blog_article2tag表
注意:以實際狀況爲準
修改homesite視圖函數,查詢個人標籤
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
刷新網頁,查看Pycharm控制檯
<QuerySet [('python全棧', 2)]>
修改homesite.html,開始渲染網頁
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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> <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> </div> </div> </div> </body> </html>
刷新網頁,效果以下:
注意:若是網頁數據沒有展現,請必定要查看數據庫是否有對應的記錄!
日期歸檔
查看Article表的create_time字段
注意:它的時間後面,有不少小數點。每一條是不同的,因此不能直接分組,不然沒有意義!
要實現這個功能,有3個小知識點:
- 1.dateformat
- 2.extra
- 3.單表分組查詢
dateformat
DATE_FORMAT() 函數用於以不一樣的格式顯示日期/時間數據。
每一個數據庫都有日期/時間 處理的函數,在MySQL中,叫dateformat。SQLite中,叫strftime
舉例:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
#截取年月日 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)
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視圖函數,增長几行代碼
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
大概意思就是,查詢建立時間大於2017-09-05的記錄
刷新網頁,查看Pycharm控制檯輸出:
1
1
1
若是條件成立,返回1。不然返回0
須要注意的是:此時已經給Article表增長一個臨時字段y_m_date。它在內存中,每次使用extra查詢纔會存在!
單表分組查詢
查詢當前用戶的全部文章,根據日期歸檔
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
解釋:
SQLite的日期格式化使用strftime,它使用2個%號來區分。
user=user 等式左邊的user是Article模型表的user屬性,也就是user_id。等式右邊的user是UserInfo表的model對象!
刷新頁面,查看Pychram控制檯輸出:
<QuerySet [('2018/07', 4)]>
修改homesite.html,開始渲染網頁
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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> <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> </div> </div> </div> </body> </html>
刷新網頁,效果以下:
左側面板添加連接
接下來,須要點擊左邊的分類、標籤、歸檔,顯示相關的文章
訪問博客園左側的分類、標籤、歸檔,方法它有一個規律
標籤:
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,完整代碼以下:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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), ]
那麼問題來了,訪問我的站點時,不須要額外的參數。
訪問分類/標籤/歸檔 這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視圖函數
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
訪問我的站點: 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視圖函數
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
修改homesite.html
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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> <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> </div> </div> </div> </body> </html>
訪問我的站點: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
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
* { 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; }
xiao.css
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
.header { width: 100%; height: 59px; background-color: #369; }
zhang.css
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
.header { width: 100%; height: 59px; background-color: green; }
修改homesite.html,修改head部分,完整代碼以下:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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> <img src="/static/img/icon_comment.gif" alt=""><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> </div> </div> </div> </body> </html>
使用谷歌瀏覽器登陸xiao的用戶,進入我的主頁
使用火狐瀏覽器登陸zhang的用戶
進入我的主頁,發現標題顏色沒有換過來
進入admin後臺,點擊users表,找到zhang用戶,發現它沒有綁定我的站點。
由於使用命令建立用戶時,blog_id字段,默認爲空!
手動綁定一下
再次刷新頁面,效果以下:
文章詳情
因爲文章詳情頁,功能繁多,必須專門作一個視圖才行。
修改urls.py,增長路徑article_detail
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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), ]
因爲文章詳情頁的左測和標題部分是通用的,須要用到模板繼承
模板繼承
新建base.html,將homesite.html的代碼複製過來,刪除多餘的部分。增長block
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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>
修改homesite.html
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{% 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> <span class="glyphicon glyphicon-comment"></span><a href="">評論({{ article.comment_count }})</a> <span class="glyphicon glyphicon-thumbs-up"></span><a href="">點贊({{ article.up_count }})</a> </div> </div> <hr> {% endfor %} </div> {% endblock %}
增長article_detail.html
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{% 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 %}
修改article_detail視圖函數
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
刷新網頁,點擊左側的一個分類,效果以下:
點擊右邊的一篇文章
關於內容部分,爲何是html標籤。這些暫時不處理,後面會講到如何處理!
查看article_detail和homesite 這2個視圖函數,有重複的代碼。在編程的過程當中,最好不要出現重複代碼,怎麼辦呢?使用函數封裝!
函數封裝
修改views.py,增長函數get_query_data。刪掉article_detail和homesite 這2個視圖函數中的重複代碼,完整代碼以下:
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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)
注意:get_query_data必需要在2個視圖函數的上面,不然沒法調用!
從新訪問網頁,效果以下:
封裝函數,有一個侷限性,若是新增變量,須要增長字典key-value。因爲繼承模板時,變量是不會繼承的。因此引用的視圖函數,必須從新傳值才能夠渲染。那麼可不能夠,將模板和數據包裝成一個模板,做爲一個總體。其餘模板繼承時,就是一個已經渲染過的模板呢?
答案是有的,那就是inclusion_tag
包含標籤(Inclusion tags)
Django過濾器和標籤功能很強大,並且支持自定義標籤,非常方便;其中一種標籤是Inclusion tags,即包含標籤
包含標籤(Inclusion tags)經過渲染其餘的模板來展現內容,這類標籤的用途在於一些類似的內容的展現,而且返回的內容是渲染其餘模板獲得的內容。
自定義標籤必須在應用名目錄下建立templatetags目錄。注意:此目錄名必須叫這個名字,不可改變。
在templatetags目錄下,建立my_tags.py,這個文件名,是能夠隨便的
先來增長一個乘法的標籤
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
from django import template register=template.Library() @register.simple_tag def mul_tag(x,y): return x*y
修改article_detail.html,調用這個自定義標籤
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{% 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 %}
必須重啓django項目,不然模板沒法引用自定義標籤!
必須重啓django項目,不然模板沒法引用自定義標籤!
必須重啓django項目,不然模板沒法引用自定義標籤!
隨便訪問一篇文章,出現一個14,說明調用成功了
那麼這個my_tags,如何渲染左側的分類,標籤,歸檔呢?
新建標籤get_query_data,必須返回一個字典
將視圖函數中的相關代碼,複製過來便可。
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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}
@register.inclusion_tag("left_region.html") 表示將返回結果渲染給left_region.html
若是在模板中有調用left_redig.html,那麼這個文件,就會渲染,是渲染後的html文件!
在templates中新建文件left_region.html
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<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>
修改base.html,將<div class="col-md-3"></div> 中的內容部分,改成引用get_query_data標籤
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
<!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>
此時刷新網頁,效果同上!
修改views.py中的視圖函數,刪除get_query_data!
刪除homesite和article_detail兩個視圖函數多餘的代碼
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
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})
注意:get_query_data標籤只是定義了左側的標籤!那麼homesite和article_detail兩個視圖函數,須要知道當前站點的博客標題。
因此須要專門定義個函數,來獲取博客標題!
修改article_detail.html,刪除測試的自定義標籤
![](http://static.javashuo.com/static/loading.gif)
![](http://static.javashuo.com/static/loading.gif)
{% 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 %}
從新訪問我的站點,隨便亂點,效果同上!
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代碼時,須要作特殊處理。
後面講到富文本編輯器,會講到。完美解決這個問題!