python个人网站开发_python 全栈开发,Day81(博客系统个人主页,文章详情页)
一、個人主頁
隨筆分類
需求:查詢當前站點每一個分類的名稱以及對應的文章數
完成這個需求,就可以展示左側的分類
它需要利用分組查詢,那么必須要會基于雙下劃線的查詢。
基于雙下劃線的查詢,簡單來講,就是用join。將多個表拼接成一張表,那么就可以單表操作了!
表關系圖
圖中箭頭開始的英文字母表示關聯字段
按照箭頭方向查詢,表示正向查詢,否則為反向查詢
分解步驟:
先來查詢每一個分類的名稱以及對應的文章數
看上面的關系圖,以Category表為基礎表來查詢Article表對應的文章數,需要用到反向查詢。
記住一個原則,正向查詢使用字段,反向查詢使用表名
修改views.py,導入相關表和聚合函數
from django.shortcuts importrender,HttpResponse,redirectfrom django.contrib importauthfrom blog.models importArticle,UserInfo,Blog,Category,Tagfrom django.db.models importSum,Avg,Max,Min,Count#Create your views here.
deflogin(request):if request.method=="POST":
user=request.POST.get("user")
pwd=request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊session
#全局變量 request.user=當前登陸對象(session中)
auth.login(request,user)return redirect("/index/")return render(request,"login.html")defindex(request):
article_list=Article.objects.all()return render(request,"index.html",{"article_list":article_list})def logout(request): #注銷
auth.logout(request)return redirect("/index/")defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser: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控制臺輸出:
上面得到了所有文章的分類以及文章數。
再來查詢當前站點每一個分類的名稱以及對應的文章數
思路:只需要對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控制臺輸出:
既然結果出來了,模板就可以渲染了
修改homesite視圖函數,完整代碼如下:
from django.shortcuts importrender,HttpResponse,redirectfrom django.contrib importauthfrom blog.models importArticle,UserInfo,Blog,Category,Tagfrom django.db.models importSum,Avg,Max,Min,Count#Create your views here.
deflogin(request):if request.method=="POST":
user=request.POST.get("user")
pwd=request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊session
#全局變量 request.user=當前登陸對象(session中)
auth.login(request,user)return redirect("/index/")return render(request,"login.html")defindex(request):
article_list=Article.objects.all()return render(request,"index.html",{"article_list":article_list})def logout(request): #注銷
auth.logout(request)return redirect("/index/")defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blogprint(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
Title*{
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;
}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
Panel content日期歸檔
Panel content{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評論({{ article.comment_count }})
點贊({{ article.up_count }}){% endfor %}
View Code
values_list返回的是一個元組,所以模板中,直接用cate.0就可以取到分類名
刷新網頁,效果如下:
我的標簽
我的標簽和隨筆的查詢語句是類似的,換一個表名,就可以了!
先在admin后臺為不同的用戶,添加標簽
由于admin后臺無法直接將博客表和標簽表做對應關系,所以只能手動綁定關系。
使用navicat打開blog_article2tag表
注意:以實際情況為準
修改homesite視圖函數,查詢我的標簽
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blogprint(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控制臺
修改homesite.html,開始渲染網頁
Title*{
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;
}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
Panel content{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評論({{ article.comment_count }})
點贊({{ article.up_count }}){% endfor %}
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.00sec)#截取年月
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視圖函數,增加幾行代碼
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blogprint(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 intest_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查詢才會存在!
單表分組查詢
查詢當前用戶的所有文章,根據日期歸檔
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blogprint(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控制臺輸出:
修改homesite.html,開始渲染網頁
Title*{
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;
}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
{% for date in date_list %}{{ date.0 }}({{ date.1 }})
{% endfor %}{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評論({{ article.comment_count }})
點贊({{ article.up_count }}){% endfor %}
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\w+)/category/(?P.*)', views.homesite),
re_path('(?P\w+)/tag/(?P.*)', views.homesite),
re_path('(?P\w+)/achrive/(?P.*)', views.homesite),
仔細觀察個人站點網頁的布局
發現,點擊不同的分類、標簽、歸檔。紅色區域和綠色區域始終不變,只有紫色區域在變動。變動區域取決于article_list變量!
那么個人站點首頁、分類、標簽、歸檔這4種url可以共用一個視圖函數homesite模板以及視圖函數。
重新修改urls.py,完整代碼如下:
from django.contrib importadminfrom django.urls importpath,re_pathfrom blog importviews
urlpatterns=[
path('admin/', admin.site.urls),
path('login/', views.login),
path('index/', views.index),
path('logout/', views.logout),
path('', views.index),#跳轉
re_path('(?P\w+)/(?Pcategory|tag|achrive)/(?P.*)/$', views.homesite),#個人站點
re_path('(?P\w+)/$', views.homesite),
]
View Code
那么問題來了,訪問個人站點時,不需要額外的參數。
訪問分類/標簽/歸檔 這2個類別是,必須要2個額外的變量。分別是類別、類別參數。
homesite視圖函數,如果分別接收呢?答案是,使用**kwargs,它可以接收可變的關鍵字參數,至少1個或者多個參數!
修改homesite.html,增加一個網頁圖標,否則待會測試時,會有2次請求。
如果網頁沒有圖標,每次會請求一次網絡請求,請求favicon.ico
在title標簽下面,增加一行
修改homesite視圖函數
def homesite(request,username,**kwargs):"""查詢
:param request:
:param username:
:return:"""
print("kwargs", kwargs)#查詢當前站點的用戶對象
user=UserInfo.objects.filter(username=username).first()if notuser: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 notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blog#查詢當前用戶發布的所有文章
if notkwargs:
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
Title*{
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;
}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
{% for date in date_list %}{{ date.0 }}({{ date.1 }})
{% endfor %}{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評論({{ article.comment_count }})
點贊({{ article.up_count }}){% endfor %}
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部分,完整代碼如下:
Title{#公共樣式#}
{#個人站點主題樣式#}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
{% for date in date_list %}{{ date.0 }}({{ date.1 }})
{% endfor %}{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評論({{ article.comment_count }})
點贊({{ article.up_count }}){% endfor %}
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\w+)/articles/(?P\d+)/$', views.article_detail),#跳轉
re_path('(?P\w+)/(?Pcategory|tag|achrive)/(?P.*)/$', views.homesite),#個人站點
re_path('(?P\w+)/$', views.homesite),
]
View Code
由于文章詳情頁的左測和標題部分是通用的,需要用到模板繼承
模板繼承
新建base.html,將homesite.html的代碼復制過來,刪除多余的部分。增加block
Title{#公共樣式#}{#個人站點主題樣式#}
{#bootstrap#}
{{ blog.title }}
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
{% for date in date_list %}{{ date.0 }}({{ date.1 }})
{% endfor %}{% block content %}{% endblock %}
View Code
修改homesite.html
{% extends "base.html" %}
{% block content %}
{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發布于{{ article.create_time|date:'Y-m-d H:i' }}??評論({{ article.comment_count }})??點贊({{ article.up_count }}){% endfor %}{% endblock %}
View Code
增加article_detail.html
{% extends "base.html" %}
{% block content %}
{{ article_obj.title }}
{{ article_obj.content }}{% endblock %}View Code
修改article_detail視圖函數
defarticle_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 importrender,HttpResponse,redirectfrom django.contrib importauthfrom blog.models importArticle,UserInfo,Blog,Category,Tagfrom django.db.models importSum,Avg,Max,Min,Count#Create your views here.
deflogin(request):if request.method=="POST":
user=request.POST.get("user")
pwd=request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊session
#全局變量 request.user=當前登陸對象(session中)
auth.login(request,user)return redirect("/index/")return render(request,"login.html")defindex(request):
article_list=Article.objects.all()return render(request,"index.html",{"article_list":article_list})def logout(request): #注銷
auth.logout(request)return redirect("/index/")defget_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 notuser:return render(request,"not_found.html")#查詢當前站點對象
blog=user.blog#查詢當前用戶發布的所有文章
if notkwargs:
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)defarticle_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 importtemplate
register=template.Library()
@register.simple_tagdefmul_tag(x,y):return x*y
View Code
修改article_detail.html,調用這個自定義標簽
{% extends "base.html" %}
{% block content %}
{% load my_tags %}
{% mul_tag 2 7 %}
{{ article_obj.title }}
{{ article_obj.content }}{% endblock %}View Code
必須重啟django項目,否則模板無法引用自定義標簽!
必須重啟django項目,否則模板無法引用自定義標簽!
必須重啟django項目,否則模板無法引用自定義標簽!
隨便訪問一篇文章,出現一個14,說明調用成功了
那么這個my_tags,如何渲染左側的分類,標簽,歸檔呢?
新建標簽get_query_data,必須返回一個字典
將視圖函數中的相關代碼,復制過來即可。
from django importtemplate
register=template.Library()
@register.simple_tagdefmul_tag(x,y):return x*yfrom blog.models importCategory,Tag,Article,UserInfofrom django.db.models importCount,Avg,Max
@register.inclusion_tag("left_region.html")defget_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
隨筆分類
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
{% for date in date_list %}{{ date.0 }}({{ date.1 }})
{% endfor %}View Code
修改base.html,將
Title{#公共樣式#}{#個人站點主題樣式#}
{#bootstrap#}
{{ blog.title }}
{#加載自定義標簽模塊#}{% load my_tags %}
{#調用get_query_data標簽,它返回left_region.html,是已經被渲染過的文件#}
{% get_query_data username %}
{% block content %}{% endblock %}
View Code
此時刷新網頁,效果同上!
修改views.py中的視圖函數,刪除get_query_data!
刪除homesite和article_detail兩個視圖函數多余的代碼
from django.shortcuts importrender,HttpResponse,redirectfrom django.contrib importauthfrom blog.models importArticle,UserInfo,Blog,Category,Tagfrom django.db.models importSum,Avg,Max,Min,Count#Create your views here.
deflogin(request):if request.method=="POST":
user=request.POST.get("user")
pwd=request.POST.get("pwd")#用戶驗證成功,返回user對象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊session
#全局變量 request.user=當前登陸對象(session中)
auth.login(request,user)return redirect("/index/")return render(request,"login.html")defindex(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 notuser:return render(request, "not_found.html")#查詢當前站點對象
blog =user.blogreturnblogdef homesite(request,username,**kwargs):"""查詢
:param request:
:param username:
:return:"""
print("kwargs", kwargs)
blog=query_current_site(request,username)#查詢當前用戶發布的所有文章
if notkwargs:
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})defarticle_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 %}
{{ article_obj.title }}
{{ article_obj.content }}{% 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代碼
重新刷新頁面,它會有一個提示框
注意:它只會彈一次。如果是下面這段代碼呢?
數據庫記錄如下:
刷新頁面試試?不用想了,你今天啥事不用干,瘋狂的點擊吧!
那么既要網頁安全,又需要網站展示真實的內容,怎么辦呢?
答案就是:數據庫不存儲html代碼即可!存html和js代碼時,需要做特殊處理。
后面講到富文本編輯器,會講到。完美解決這個問題!
總結
以上是生活随笔為你收集整理的python个人网站开发_python 全栈开发,Day81(博客系统个人主页,文章详情页)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 博美多少钱一只啊?
- 下一篇: sql如何让计算出来的结果百分数显示_图