文章詳情頁
一、文章詳情頁訪問設計
訪問文章詳情頁,訪問文章路徑類似:https://www.cnblogs.com/wupeiqi/articles/3148888.html
參照訪問路徑編寫文章詳情頁路由如下:
urlpatterns = [ ... # 文章詳情頁 re_path(‘^(?P<username>\w+)/articles/(?P<article_id>\d+)$‘, views.article_detail), ]
二、文章詳情頁的數據構建
文章詳情頁的head部分和左側區域應該和個人站點保持一致。因此需要用到繼承extend。
1、創建並編寫base.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <!-- 引入 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="/static/blog/bootstrap-3.3.7/css/bootstrap.css"> <!-- jQuery (Bootstrap 的所有 JavaScript 插件都依賴 jQuery,所以必須放在前邊) --> <script src="/static/js/jquery-3.3.1.js"></script> <!-- 引入 Bootstrap 核心 JavaScript 文件 --> <script src="/static/blog/bootstrap-3.3.7/js/bootstrap.js"></script> <!--依賴jquery--> <style> * { margin: 0; padding: 0; } .header { width: 100%; height: 60px; background-color: #369; } .header .title { font-size: 18px; /* 字體大小 */ font-weight: 100; /* 字體粗細 */ line-height: 60px; /* 行高與頁頭一致,完成居中 */ color: white; margin-left: 15px; margin-top: -10px; } .backend { float: right; /* 浮動到右邊 */ color: white; text-decoration: none; /* 去除下劃線 */ font-size: 16px; margin-right: 12px; margin-top: 10px; } .pub_info { margin-top: 10px; color: darkgray; } </style> </head> <body> <div class="header"> <div class="content"> <!--站點標題--> <p class="title"> <span>{{ blog.title }}</span> <a href="" class="backend">管理</a> </p> </div> </div> <div class="container"> <div class="row"> <div class="col-md-3"> <!--添加bootstrap面板--> <div class="panel panel-warning"> <div class="panel-heading">我的標簽</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-danger"> <div class="panel-heading">隨筆分類</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-success"> <div class="panel-heading">隨筆歸檔</div> <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div> </div> </div> <div class="col-md-9"> {% block content %} {% endblock %} </div> </div> </div> </body> </html>
註意:base.html保留了原先home_site.html大部分代碼,將col-md-9的部分替換為如下:
<div class="col-md-9"> {% block content %} {% endblock %} </div>
block
告訴模版引擎: 子模版可能會覆蓋掉模版中的這些位置。
2、修改home_site.html繼承base.html
{% extends ‘base.html‘ %} {% block content %} <div class="article_list"> <div class="article_list"> {% for article in article_list %} <div class="article-item clearfix"> <h5><a href="">{{ article.title }}</a></h5> <div class="article-desc"> {# 文章摘要 #} {{ article.desc }} </div> <!--文章下方詳細信息--> <div class="small pub_info pull-right"> {# 文章發布時間 #} <span>發布於 {{ article.create_time|date:"Y-m-d H:i" }}</span> {# 評論數 #} <span class="glyphicon glyphicon-comment"></span> 評論({{ article.comment_count }}) {# 點贊數 #} <span class="glyphicon glyphicon-thumbs-up"></span> 點贊({{ article.up_count }}) </div> </div> <hr> {% endfor %} </div> </div> {% endblock %}
extends
標簽是這裏的關鍵。它告訴模版引擎,這個模版“繼承”了另一個模版。當模版系統處理這個模版時,首先將定位父模版——在此例中,就是“base.html”。
模版引擎將註意到 base.html
中的 block
標簽,並用子模版中的內容來替換這些block。
3、詳情頁面head部分和左側區域數據引入
(1)方法一
由於home_site.html和article_detail.html都需要引入如下數據:
user = UserInfo.objects.filter(username=username).first() blog = user.blog cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")) .values_list("title", "c") tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")) .values_list("title", "c") date_list = models.Article.objects.filter(user=user).extra(select={"y_m_date": "date_format(create_time, ‘%%Y-%%m‘)"}) .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c")
在views.py中定義一個新的函數get_classification_data:
def get_classification_data(username): user = UserInfo.objects.filter(username=username).first() blog = user.blog cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")) .values_list("title", "c") tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")) .values_list("title", "c") date_list = models.Article.objects.filter(user=user).extra( select={"y_m_date": "date_format(create_time, ‘%%Y-%%m‘)"}) .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c") return {"blog": blog, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list}
依此可以改寫視圖函數home_site和article_detail,以article_detail為例:
def article_detail(request, username, article_id): context = get_classification_data(username) return render(request, "article_detail.html", context)
方法二:運用inclusion_tag
在cnblog/blog/目錄下創建templatestags目錄,再創建my_tags.py文件。
(1)先快速創建簡單tag,簡單tag:只帶一個參數,返回經過處理的字符串
Django提供了一種simple_tag方法來快速創建類似這樣的tag。
from django import template register = template.Library() # 乘法的函數 @register.simple_tag def multi_tag(x,y): return x*y
修改article_detail.html,load用來載入一個過濾器或者tag, 在這裏引入my_tags:
{% extends "base.html" %} {% block content %} {% load my_tags %} {% multi_tag 3 9 %} {% endblock %}
顯示效果如下所示:
(2)創建inclusion tag
樣式和數據結合為一個整體的時候可以考慮使用inclusion_tag.
my_tags.py:
from django import template from django.db.models import Count from blog import models register = template.Library() # 乘法的函數 @register.simple_tag def multi_tag(x,y): return x*y @register.inclusion_tag("classification.html") def get_classification_style(username): user = models.UserInfo.objects.filter(username=username).first() blog = user.blog cate_list = models.Category.objects.filter(blog=blog).values("pk").annotate(c=Count("article__title")) .values_list("title", "c") tag_list = models.Tag.objects.filter(blog=blog).values("pk").annotate(c=Count("article")) .values_list("title", "c") date_list = models.Article.objects.filter(user=user).extra( select={"y_m_date": "date_format(create_time, ‘%%Y-%%m‘)"}) .values("y_m_date").annotate(c=Count("nid")).values_list("y_m_date", "c") return {"username": username, "blog": blog, "cate_list": cate_list, "tag_list": tag_list, "date_list": date_list}
將base.html中左側邊欄的面板代碼內容取出,放置於classification.html中:
base.html:
<body> <div class="header"> <div class="content"> <!--站點標題--> <p class="title"> <span>{{ blog.title }}</span> <a href="" class="backend">管理</a> </p> </div> </div> <div class="container"> <div class="row"> <div class="col-md-3"> <!--添加bootstrap面板--> {% load my_tags %} {% get_classification_style username %} </div> <div class="col-md-9"> {% block content %} {% endblock %} </div> </div> </div> </body>
classification.html:
<div> <div class="panel panel-warning"> <div class="panel-heading">我的標簽</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-danger"> <div class="panel-heading">隨筆分類</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-success"> <div class="panel-heading">隨筆歸檔</div> <div class="panel-body"> {% for date in date_list %} <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p> {% endfor %} </div> </div> </div>
修改article_detail視圖函數:
def article_detail(request, username, article_id): # context = get_classification_data(username) # return render(request, "article_detail.html", context) return render(request, "article_detail.html", locals())
三、文章詳情頁渲染的標簽字符串轉義
Django的模板中會對HTML標簽和JS等語法標簽進行自動轉義,原因顯而易見,這樣是為了安全。但是有的時候我們可能不希望這些HTML元素被轉義,比如我們做一個內容管理系統,後臺添加的文章中是經過修飾的,這些修飾可能是通過一個類似於FCKeditor編輯加註了HTML修飾符的文本,如果自動轉義的話顯示的就是保護HTML標簽的源文件。
1、article_detail視圖函數中應拿到文章對象傳入模板中
def article_detail(request, username, article_id): user = UserInfo.objects.filter(username=username).first() blog = user.blog article_obj = models.Article.objects.filter(pk=article_id).first() return render(request, "article_detail.html", locals())
2、模板語法一旦檢查到標簽字符串都會進行轉義
首先需要確認網站文章內容保存的並不是一個文本,而是一堆標簽字符串。這樣編輯文章時才會有各種各樣的樣式。
將文章內容直接傳進模板中。
{% extends "base.html" %} {% block content %} <h3 class="text-center">{{ article_obj.title }}</h3> <div class="cont"> {{ article_obj.content }} </div> {% endblock %}article_detail.html
但是直接復制網站的html源代碼進文章內容中,顯示是不正確的。
如上所示:將<h1>hello</h1>存進數據庫,當服務器傳給瀏覽器的時候,卻變成了<h1>hello</h>,瀏覽器按特殊符號渲染,因此顯示為<h1>hello</h1>。
由此可見,模板語法一旦檢查到標簽字符串都會進行轉義。
3、在Django中關閉HTML的自動轉義
如果是一個單獨的變量我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉義。比如:
<p>這行代表會被自動轉義</p>: {{ data }} <p>這行代表不會被自動轉義</p>: {{ data|safe }}
其中第二行我們關閉了Django的自動轉義。
我們還可以通過{%autoescape off%}的方式關閉整段代碼的自動轉義,比如下面這樣:
{% autoescape off %} Hello {{ name }} {% endautoescape %}
文章詳情頁