python个人网站开发_python 全栈开发,Day81(博客系统个人主页,文章详情页)
一、個(gè)人主頁(yè)
隨筆分類(lèi)
需求:查詢當(dāng)前站點(diǎn)每一個(gè)分類(lèi)的名稱以及對(duì)應(yīng)的文章數(shù)
完成這個(gè)需求,就可以展示左側(cè)的分類(lèi)
它需要利用分組查詢,那么必須要會(huì)基于雙下劃線的查詢。
基于雙下劃線的查詢,簡(jiǎn)單來(lái)講,就是用join。將多個(gè)表拼接成一張表,那么就可以單表操作了!
表關(guān)系圖
圖中箭頭開(kāi)始的英文字母表示關(guān)聯(lián)字段
按照箭頭方向查詢,表示正向查詢,否則為反向查詢
分解步驟:
先來(lái)查詢每一個(gè)分類(lèi)的名稱以及對(duì)應(yīng)的文章數(shù)
看上面的關(guān)系圖,以Category表為基礎(chǔ)表來(lái)查詢Article表對(duì)應(yīng)的文章數(shù),需要用到反向查詢。
記住一個(gè)原則,正向查詢使用字段,反向查詢使用表名
修改views.py,導(dǎo)入相關(guān)表和聚合函數(shù)
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")#用戶驗(yàn)證成功,返回user對(duì)象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊(cè)session
#全局變量 request.user=當(dāng)前登陸對(duì)象(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): #注銷(xiāo)
auth.logout(request)return redirect("/index/")defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blog#查詢當(dāng)前用戶發(fā)布的所有文章
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來(lái)分組,得到分類(lèi)名以及統(tǒng)計(jì)數(shù)
多添加幾篇文章,給另外一個(gè)用戶也添加幾篇文章
訪問(wèn)個(gè)人站點(diǎn):http://127.0.0.1:8000/xiao/
查看Pycharm控制臺(tái)輸出:
上面得到了所有文章的分類(lèi)以及文章數(shù)。
再來(lái)查詢當(dāng)前站點(diǎn)每一個(gè)分類(lèi)的名稱以及對(duì)應(yīng)的文章數(shù)
思路:只需要對(duì)Category表進(jìn)行篩選,過(guò)濾中當(dāng)前站點(diǎn)用戶的分類(lèi)
在homesite視圖函數(shù)中,已經(jīng)有一個(gè)當(dāng)前站點(diǎn)的blog對(duì)象。
在Category模型表中,有一個(gè)blog屬性,它和blog是一對(duì)多關(guān)系。那么只需要blog=blog,就可以了
修改視圖函數(shù)homesite的ret變量
ret = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values("title","c")
注意:等式左邊的blog表示Category模型表的blog屬性,實(shí)際上就是blog_id字段
等式右邊的是blog變量,它是一個(gè)model對(duì)象。那么blog=blog,就可以查詢出,當(dāng)前站點(diǎn)的分類(lèi)了!
刷新網(wǎng)頁(yè),查看Pycharm控制臺(tái)輸出:
既然結(jié)果出來(lái)了,模板就可以渲染了
修改homesite視圖函數(shù),完整代碼如下:
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")#用戶驗(yàn)證成功,返回user對(duì)象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊(cè)session
#全局變量 request.user=當(dāng)前登陸對(duì)象(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): #注銷(xiāo)
auth.logout(request)return redirect("/index/")defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blogprint(blog,type(blog))#查詢當(dāng)前用戶發(fā)布的所有文章
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 }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
Panel content日期歸檔
Panel content{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評(píng)論({{ article.comment_count }})
點(diǎn)贊({{ article.up_count }}){% endfor %}
View Code
values_list返回的是一個(gè)元組,所以模板中,直接用cate.0就可以取到分類(lèi)名
刷新網(wǎng)頁(yè),效果如下:
我的標(biāo)簽
我的標(biāo)簽和隨筆的查詢語(yǔ)句是類(lèi)似的,換一個(gè)表名,就可以了!
先在admin后臺(tái)為不同的用戶,添加標(biāo)簽
由于admin后臺(tái)無(wú)法直接將博客表和標(biāo)簽表做對(duì)應(yīng)關(guān)系,所以只能手動(dòng)綁定關(guān)系。
使用navicat打開(kāi)blog_article2tag表
注意:以實(shí)際情況為準(zhǔn)
修改homesite視圖函數(shù),查詢我的標(biāo)簽
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blogprint(blog,type(blog))#查詢當(dāng)前用戶發(fā)布的所有文章
article_list=Article.objects.filter(user__username=username)#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")print(cate_list)#我的標(biāo)簽
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
刷新網(wǎng)頁(yè),查看Pycharm控制臺(tái)
修改homesite.html,開(kāi)始渲染網(wǎng)頁(yè)
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 }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% for tag in tag_list %}{{ tag.0 }}({{ tag.1 }})
{% endfor %}日期歸檔
Panel content{% for article in article_list %}{{ article.title }}
{{ article.desc }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評(píng)論({{ article.comment_count }})
點(diǎn)贊({{ article.up_count }}){% endfor %}
View Code
刷新網(wǎng)頁(yè),效果如下:
注意:如果網(wǎng)頁(yè)數(shù)據(jù)沒(méi)有展示,請(qǐng)一定要查看數(shù)據(jù)庫(kù)是否有對(duì)應(yīng)的記錄!
日期歸檔
查看Article表的create_time字段
注意:它的時(shí)間后面,有很多小數(shù)點(diǎn)。每一條是不一樣的,所以不能直接分組,否則沒(méi)有意義!
要實(shí)現(xiàn)這個(gè)功能,有3個(gè)小知識(shí)點(diǎn):
1.dateformat
2.extra
3.單表分組查詢
dateformat
DATE_FORMAT() 函數(shù)用于以不同的格式顯示日期/時(shí)間數(shù)據(jù)。
每個(gè)數(shù)據(jù)庫(kù)都有日期/時(shí)間 處理的函數(shù),在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的查詢語(yǔ)法難以表達(dá)復(fù)雜的where子句,對(duì)于這種情況, Django 提供了extra()QuerySet修改機(jī)制 。它能在QuerySet生成的SQL從句中注入新子句,extra可以指定一個(gè)或多個(gè)參數(shù),例如select、where或tables。 這些參數(shù)都不是必須的,但是至少要使用一個(gè)。
語(yǔ)法:
extra(select=None, where=None, params=None,
tables=None, order_by=None, select_params=None)
select參數(shù)
select參數(shù)可以在select從句中添加其他字段信息,它應(yīng)該是一個(gè)字典,存放著屬性名到 SQL 從句的映射。
舉例:
修改homesite視圖函數(shù),增加幾行代碼
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blogprint(blog,type(blog))#查詢當(dāng)前用戶發(fā)布的所有文章
article_list=Article.objects.filter(user__username=username)#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")print(cate_list)#我的標(biāo)簽
tag_list = Tag.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")print(tag_list)#測(cè)試日期
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
大概意思就是,查詢創(chuàng)建時(shí)間大于2017-09-05的記錄
刷新網(wǎng)頁(yè),查看Pycharm控制臺(tái)輸出:
1
1
1
如果條件成立,返回1。否則返回0
需要注意的是:此時(shí)已經(jīng)給Article表增加一個(gè)臨時(shí)字段y_m_date。它在內(nèi)存中,每次使用extra查詢才會(huì)存在!
單表分組查詢
查詢當(dāng)前用戶的所有文章,根據(jù)日期歸檔
defhomesite(request,username):"""查詢
:param request:
:param username:
:return:"""
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blogprint(blog,type(blog))#查詢當(dāng)前用戶發(fā)布的所有文章
article_list=Article.objects.filter(user__username=username)#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")print(cate_list)#我的標(biāo)簽
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個(gè)%號(hào)來(lái)區(qū)分。
user=user? 等式左邊的user是Article模型表的user屬性,也就是user_id。等式右邊的user是UserInfo表的model對(duì)象!
刷新頁(yè)面,查看Pychram控制臺(tái)輸出:
修改homesite.html,開(kāi)始渲染網(wǎng)頁(yè)
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 }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% 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 }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評(píng)論({{ article.comment_count }})
點(diǎn)贊({{ article.up_count }}){% endfor %}
View Code
刷新網(wǎng)頁(yè),效果如下:
左側(cè)面板添加鏈接
接下來(lái),需要點(diǎn)擊左邊的分類(lèi)、標(biāo)簽、歸檔,顯示相關(guān)的文章
訪問(wèn)博客園左側(cè)的分類(lèi)、標(biāo)簽、歸檔,方法它有一個(gè)規(guī)律
標(biāo)簽:
http://www.cnblogs.com/用戶名/tag/標(biāo)簽名/
分類(lèi):
https://www.cnblogs.com/用戶名/category/分類(lèi)id.html
歸檔:
https://www.cnblogs.com/用戶名/archive/年/月.html
修改urls.py,增加3個(gè)路徑。注意要導(dǎo)入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),
仔細(xì)觀察個(gè)人站點(diǎn)網(wǎng)頁(yè)的布局
發(fā)現(xiàn),點(diǎn)擊不同的分類(lèi)、標(biāo)簽、歸檔。紅色區(qū)域和綠色區(qū)域始終不變,只有紫色區(qū)域在變動(dòng)。變動(dòng)區(qū)域取決于article_list變量!
那么個(gè)人站點(diǎn)首頁(yè)、分類(lèi)、標(biāo)簽、歸檔這4種url可以共用一個(gè)視圖函數(shù)homesite模板以及視圖函數(shù)。
重新修改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),#跳轉(zhuǎn)
re_path('(?P\w+)/(?Pcategory|tag|achrive)/(?P.*)/$', views.homesite),#個(gè)人站點(diǎn)
re_path('(?P\w+)/$', views.homesite),
]
View Code
那么問(wèn)題來(lái)了,訪問(wèn)個(gè)人站點(diǎn)時(shí),不需要額外的參數(shù)。
訪問(wèn)分類(lèi)/標(biāo)簽/歸檔 這2個(gè)類(lèi)別是,必須要2個(gè)額外的變量。分別是類(lèi)別、類(lèi)別參數(shù)。
homesite視圖函數(shù),如果分別接收呢?答案是,使用**kwargs,它可以接收可變的關(guān)鍵字參數(shù),至少1個(gè)或者多個(gè)參數(shù)!
修改homesite.html,增加一個(gè)網(wǎng)頁(yè)圖標(biāo),否則待會(huì)測(cè)試時(shí),會(huì)有2次請(qǐng)求。
如果網(wǎng)頁(yè)沒(méi)有圖標(biāo),每次會(huì)請(qǐng)求一次網(wǎng)絡(luò)請(qǐng)求,請(qǐng)求favicon.ico
在title標(biāo)簽下面,增加一行
修改homesite視圖函數(shù)
def homesite(request,username,**kwargs):"""查詢
:param request:
:param username:
:return:"""
print("kwargs", kwargs)#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blog#查詢當(dāng)前用戶發(fā)布的所有文章
article_list=Article.objects.filter(user__username=username)#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")#print(cate_list)
#我的標(biāo)簽
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
訪問(wèn)個(gè)人站點(diǎn):?http://127.0.0.1:8000/xiao/
Pycharm控制臺(tái)輸出:kwargs {}
訪問(wèn)個(gè)人分類(lèi)python:?http://127.0.0.1:8000/xiao/category/python/
Pycharm控制臺(tái)輸出:kwargs {'params': 'python/', 'condition': 'category'}
訪問(wèn)個(gè)人標(biāo)簽:?http://127.0.0.1:8000/xiao/tag/python全棧/
Pycharm控制臺(tái)輸出:kwargs {'params': 'python全棧/', 'condition': 'tag'}
訪問(wèn)個(gè)人歸檔:?http://127.0.0.1:8000/xiao/achrive/2018/07
Pycharm控制臺(tái)輸出:kwargs {'params': '2018/07', 'condition': 'achrive'}
注意:要帶上用戶名,否則出現(xiàn)404錯(cuò)誤
那么,只需要判斷kwargs變量,就可以區(qū)分了!
修改homesite視圖函數(shù)
def homesite(request,username,**kwargs):"""查詢
:param request:
:param username:
:return:"""
print("kwargs", kwargs)#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blog#查詢當(dāng)前用戶發(fā)布的所有文章
if notkwargs:
article_list= Article.objects.filter(user__username=username)else:
condition= kwargs.get("condition")
params= kwargs.get("params")#判斷分類(lèi)、隨筆、歸檔
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)#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")#print(cate_list)
#我的標(biāo)簽
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 }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% 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 }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評(píng)論({{ article.comment_count }})
點(diǎn)贊({{ article.up_count }}){% endfor %}
View Code
訪問(wèn)個(gè)人站點(diǎn):http://127.0.0.1:8000/xiao/
效果如下:
主題切換
查看blog_blog表,有2條記錄
theme對(duì)應(yīng)主題的css文件
在homesite.html中的style標(biāo)簽定義了一些樣式。現(xiàn)在需要分離出來(lái)!
每一個(gè)用戶有自己的標(biāo)題顏色,比如xiao用默認(rèn)的藍(lán)色,zhang用綠色
在static中新建css目錄,在css中新建文件夾theme,新建3個(gè)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{#公共樣式#}
{#個(gè)人站點(diǎn)主題樣式#}
{{ blog.title }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% 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 }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??href="">評(píng)論({{ article.comment_count }})
點(diǎn)贊({{ article.up_count }}){% endfor %}
View Code
使用谷歌瀏覽器登錄xiao的用戶,進(jìn)入個(gè)人主頁(yè)
使用火狐瀏覽器登錄zhang的用戶
進(jìn)入個(gè)人主頁(yè),發(fā)現(xiàn)標(biāo)題顏色沒(méi)有換過(guò)來(lái)
進(jìn)入admin后臺(tái),點(diǎn)擊users表,找到zhang用戶,發(fā)現(xiàn)它沒(méi)有綁定個(gè)人站點(diǎn)。
因?yàn)槭褂妹顒?chuàng)建用戶時(shí),blog_id字段,默認(rèn)為空!
手動(dòng)綁定一下
再次刷新頁(yè)面,效果如下:
文章詳情
由于文章詳情頁(yè),功能繁多,必須專(zhuān)門(mén)做一個(gè)視圖才行。
修改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),#跳轉(zhuǎn)
re_path('(?P\w+)/(?Pcategory|tag|achrive)/(?P.*)/$', views.homesite),#個(gè)人站點(diǎn)
re_path('(?P\w+)/$', views.homesite),
]
View Code
由于文章詳情頁(yè)的左測(cè)和標(biāo)題部分是通用的,需要用到模板繼承
模板繼承
新建base.html,將homesite.html的代碼復(fù)制過(guò)來(lái),刪除多余的部分。增加block
Title{#公共樣式#}{#個(gè)人站點(diǎn)主題樣式#}
{#bootstrap#}
{{ blog.title }}
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% 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 }}
發(fā)布于{{ article.create_time|date:'Y-m-d H:i' }}??評(píng)論({{ article.comment_count }})??點(diǎn)贊({{ 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視圖函數(shù)
defarticle_detail(request,username,article_id):
user= UserInfo.objects.filter(username=username).first()#查詢當(dāng)前站點(diǎn)對(duì)象
blog =user.blog#查詢指定id的文章
article_obj=Article.objects.filter(pk=article_id).first()#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")#print(cate_list)
#我的標(biāo)簽
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
刷新網(wǎng)頁(yè),點(diǎn)擊左側(cè)的一個(gè)分類(lèi),效果如下:
點(diǎn)擊右邊的一篇文章
關(guān)于內(nèi)容部分,為什么是html標(biāo)簽。這些暫時(shí)不處理,后面會(huì)講到如何處理!
查看article_detail和homesite 這2個(gè)視圖函數(shù),有重復(fù)的代碼。在編程的過(guò)程中,最好不要出現(xiàn)重復(fù)代碼,怎么辦呢?使用函數(shù)封裝!
函數(shù)封裝
修改views.py,增加函數(shù)get_query_data。刪掉article_detail和homesite 這2個(gè)視圖函數(shù)中的重復(fù)代碼,完整代碼如下:
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")#用戶驗(yàn)證成功,返回user對(duì)象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊(cè)session
#全局變量 request.user=當(dāng)前登陸對(duì)象(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): #注銷(xiāo)
auth.logout(request)return redirect("/index/")defget_query_data(request,username):
user= UserInfo.objects.filter(username=username).first()#查詢當(dāng)前站點(diǎn)對(duì)象
blog =user.blog#隨筆分類(lèi)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")#print(cate_list)
#我的標(biāo)簽
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)#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user=UserInfo.objects.filter(username=username).first()if notuser:return render(request,"not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog=user.blog#查詢當(dāng)前用戶發(fā)布的所有文章
if notkwargs:
article_list= Article.objects.filter(user__username=username)else:
condition= kwargs.get("condition")
params= kwargs.get("params")#判斷分類(lèi)、隨筆、歸檔
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) #調(diào)用函數(shù)
dict['article_list'] = article_list #增加一個(gè)key
return render(request,"homesite.html",dict)defarticle_detail(request,username,article_id):
content_text= get_query_data(request,username) #調(diào)用函數(shù)
#查詢指定id的文章
article_obj = Article.objects.filter(pk=article_id).first()
content_text['article_obj'] = article_obj #增加一個(gè)key
return render(request,'article_detail.html',content_text)
View Code
注意:get_query_data必須要在2個(gè)視圖函數(shù)的上面,否則無(wú)法調(diào)用!
重新訪問(wèn)網(wǎng)頁(yè),效果如下:
封裝函數(shù),有一個(gè)局限性,如果新增變量,需要增加字典key-value。由于繼承模板時(shí),變量是不會(huì)繼承的。所以引用的視圖函數(shù),必須重新傳值才可以渲染。那么可不可以,將模板和數(shù)據(jù)包裝成一個(gè)模板,作為一個(gè)整體。其他模板繼承時(shí),就是一個(gè)已經(jīng)渲染過(guò)的模板呢?
答案是有的,那就是inclusion_tag
包含標(biāo)簽(Inclusion tags)
Django過(guò)濾器和標(biāo)簽功能很強(qiáng)大,而且支持自定義標(biāo)簽,很是方便;其中一種標(biāo)簽是Inclusion tags,即包含標(biāo)簽
包含標(biāo)簽(Inclusion tags)通過(guò)渲染其他的模板來(lái)展示內(nèi)容,這類(lèi)標(biāo)簽的用途在于一些相似的內(nèi)容的展示,并且返回的內(nèi)容是渲染其他模板得到的內(nèi)容。
自定義標(biāo)簽必須在應(yīng)用名目錄下創(chuàng)建templatetags目錄。注意:此目錄名必須叫這個(gè)名字,不可改變。
在templatetags目錄下,創(chuàng)建my_tags.py,這個(gè)文件名,是可以隨便的
先來(lái)增加一個(gè)乘法的標(biāo)簽
from django importtemplate
register=template.Library()
@register.simple_tagdefmul_tag(x,y):return x*y
View Code
修改article_detail.html,調(diào)用這個(gè)自定義標(biāo)簽
{% extends "base.html" %}
{% block content %}
{% load my_tags %}
{% mul_tag 2 7 %}
{{ article_obj.title }}
{{ article_obj.content }}{% endblock %}View Code
必須重啟django項(xiàng)目,否則模板無(wú)法引用自定義標(biāo)簽!
必須重啟django項(xiàng)目,否則模板無(wú)法引用自定義標(biāo)簽!
必須重啟django項(xiàng)目,否則模板無(wú)法引用自定義標(biāo)簽!
隨便訪問(wèn)一篇文章,出現(xiàn)一個(gè)14,說(shuō)明調(diào)用成功了
那么這個(gè)my_tags,如何渲染左側(cè)的分類(lèi),標(biāo)簽,歸檔呢?
新建標(biāo)簽get_query_data,必須返回一個(gè)字典
將視圖函數(shù)中的相關(guān)代碼,復(fù)制過(guò)來(lái)即可。
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()#查詢當(dāng)前站點(diǎn)對(duì)象
blog =user.blog#查詢當(dāng)前站點(diǎn)每一個(gè)分類(lèi)的名稱以及對(duì)應(yīng)的文章數(shù)
cate_list = Category.objects.filter(blog=blog).annotate(c=Count("article__title")).values_list("title", "c")#print(cate_list)
#查詢當(dāng)前站點(diǎn)每一個(gè)標(biāo)簽的名稱以及對(duì)應(yīng)的文章數(shù)
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") 表示將返回結(jié)果渲染給left_region.html
如果在模板中有調(diào)用left_redig.html,那么這個(gè)文件,就會(huì)渲染,是渲染后的html文件!
在templates中新建文件left_region.html
隨筆分類(lèi)
{% for cate in cate_list %}{{ cate.0 }}({{ cate.1 }})
{% endfor %}我的標(biāo)簽
{% 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{#公共樣式#}{#個(gè)人站點(diǎn)主題樣式#}
{#bootstrap#}
{{ blog.title }}
{#加載自定義標(biāo)簽?zāi)K#}{% load my_tags %}
{#調(diào)用get_query_data標(biāo)簽,它返回left_region.html,是已經(jīng)被渲染過(guò)的文件#}
{% get_query_data username %}
{% block content %}{% endblock %}
View Code
此時(shí)刷新網(wǎng)頁(yè),效果同上!
修改views.py中的視圖函數(shù),刪除get_query_data!
刪除homesite和article_detail兩個(gè)視圖函數(shù)多余的代碼
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")#用戶驗(yàn)證成功,返回user對(duì)象,否則返回None
user=auth.authenticate(username=user,password=pwd)ifuser:#登錄,注冊(cè)session
#全局變量 request.user=當(dāng)前登陸對(duì)象(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): #注銷(xiāo)
auth.logout(request)return redirect("/index/")def query_current_site(request,username): #查詢當(dāng)前站點(diǎn)的博客標(biāo)題
#查詢當(dāng)前站點(diǎn)的用戶對(duì)象
user = UserInfo.objects.filter(username=username).first()if notuser:return render(request, "not_found.html")#查詢當(dāng)前站點(diǎn)對(duì)象
blog =user.blogreturnblogdef homesite(request,username,**kwargs):"""查詢
:param request:
:param username:
:return:"""
print("kwargs", kwargs)
blog=query_current_site(request,username)#查詢當(dāng)前用戶發(fā)布的所有文章
if notkwargs:
article_list= Article.objects.filter(user__username=username)else:
condition= kwargs.get("condition")
params= kwargs.get("params")#判斷分類(lèi)、隨筆、歸檔
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標(biāo)簽只是定義了左側(cè)的標(biāo)簽!那么homesite和article_detail兩個(gè)視圖函數(shù),需要知道當(dāng)前站點(diǎn)的博客標(biāo)題。
所以需要專(zhuān)門(mén)定義個(gè)函數(shù),來(lái)獲取博客標(biāo)題!
修改article_detail.html,刪除測(cè)試的自定義標(biāo)簽
{% extends "base.html" %}
{% block content %}
{{ article_obj.title }}
{{ article_obj.content }}{% endblock %}View Code
重新訪問(wèn)個(gè)人站點(diǎn),隨便亂點(diǎn),效果同上!
Inclusion tags的優(yōu)點(diǎn):
1.不用在視圖函數(shù)中return字典
2.數(shù)據(jù)和樣式結(jié)合在一起,返回一個(gè)渲染后的html
詳情頁(yè)顯示html代碼問(wèn)題
訪問(wèn)一篇博客詳情,比如:
http://127.0.0.1:8000/xiao/articles/5/
效果如下:
那么django響應(yīng)給瀏覽器的,真的是原來(lái)的html代碼嗎?
修改id為5的文章記錄,修改content字段的數(shù)據(jù),先備份一下,改成一個(gè)h1標(biāo)簽。
刷新網(wǎng)頁(yè),效果如下:
打開(kāi)瀏覽器控制臺(tái)-->network,查看這次請(qǐng)求的響應(yīng)體
發(fā)現(xiàn)代碼被轉(zhuǎn)義了!那么是誰(shuí)轉(zhuǎn)義了呢?當(dāng)然是....
注意:這不是瀏覽器的鍋,是django轉(zhuǎn)義的,這是它的安全策略做的。遇到html或者js代碼,會(huì)自動(dòng)轉(zhuǎn)義!
那么我們不要django轉(zhuǎn)義呢?使用safe過(guò)濾器即可!
修改article_detail.html中的代碼
{{ article_obj.content|safe }}
重新刷新頁(yè)面,效果如下:
注意:這樣有一個(gè)安全隱患!
舉例:將內(nèi)容修改為一段js代碼
重新刷新頁(yè)面,它會(huì)有一個(gè)提示框
注意:它只會(huì)彈一次。如果是下面這段代碼呢?
數(shù)據(jù)庫(kù)記錄如下:
刷新頁(yè)面試試?不用想了,你今天啥事不用干,瘋狂的點(diǎn)擊吧!
那么既要網(wǎng)頁(yè)安全,又需要網(wǎng)站展示真實(shí)的內(nèi)容,怎么辦呢?
答案就是:數(shù)據(jù)庫(kù)不存儲(chǔ)html代碼即可!存html和js代碼時(shí),需要做特殊處理。
后面講到富文本編輯器,會(huì)講到。完美解決這個(gè)問(wèn)題!
總結(jié)
以上是生活随笔為你收集整理的python个人网站开发_python 全栈开发,Day81(博客系统个人主页,文章详情页)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 博美多少钱一只啊?
- 下一篇: sql如何让计算出来的结果百分数显示_图