1. 程式人生 > >文章詳情頁

文章詳情頁

filter 關閉 管理系 cts char 整體 面板 rst lec

一、文章詳情頁訪問設計

  訪問文章詳情頁,訪問文章路徑類似: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>存進數據庫,當服務器傳給瀏覽器的時候,卻變成了&lt;h1&gt;hello&lt;/h&gt;,瀏覽器按特殊符號渲染,因此顯示為<h1>hello</h1>。

  技術分享圖片

  由此可見,模板語法一旦檢查到標簽字符串都會進行轉義。

3、在Django中關閉HTML的自動轉義

  如果是一個單獨的變量我們可以通過過濾器“|safe”的方式告訴Django這段代碼是安全的不必轉義。比如:

<p>這行代表會被自動轉義</p>: {{ data }}
<p>這行代表不會被自動轉義</p>: {{ data|safe }}

  其中第二行我們關閉了Django的自動轉義。
  我們還可以通過{%autoescape off%}的方式關閉整段代碼的自動轉義,比如下面這樣:

{% autoescape off %}
    Hello {{ name }}
{% endautoescape %}

  

文章詳情頁