Django學習筆記(20)——BBS+Blog專案開發(4)Django如何使用Bootstrap

戰爭熱誠發表於2019-06-27

  本文學習如何通過Django使用Bootstrap。其實在之前好幾個Django專案中已經嘗試使用過了Bootstrap,而且都留有學習記錄,我已經大概有了一個大的框架,那麼本文就從頭再走一遍流程,其實主要細節還是Bootstrap的常用的語法使用。除了基本流程,本文基於BBS+Blog專案進行學習,主要是完成其專案的模板的功能,順帶學習一下Bootstrap的內容。

  我使用的Python版本為3.X,Bootstrap版本為3.3.31,Django版本為2.0。

  模板語法不懂的可以參考部落格:Django學習筆記(3)——表單,路由控制和模板語法的學習

1,下載及配置Bootstrap相關檔案

  點選:Bootstrap官網下載連結

  我們選擇第一個,或者第二個都可以:兩者的區別就是原始碼內容更加完善,而用於生產的比較輕便。

  我們可以看看兩者的目錄結構。

1.1,Bootstrap預編譯版的基本檔案結構:

  預編譯檔案可以直接使用到任何web專案中。官方提供了編譯好的CSS和JS(bootstrap.*)檔案,還有經過壓縮的CSS和JS(bootstrap.*)檔案。同時還提供了CSS原始碼對映表(bootstrap.*.map),可以在某些瀏覽器的開發工具中使用。

1.2,Bootstrap原始碼的基本檔案結構:

 

  當然,有時候我們做測試的時候,也可以直接使用CDN。

1.3 Bootstrap的CDN

  Bootstrap中文網為Bootstrap專門構建了免費的CDN加速服務,訪問速度更快,加速效果更明顯,沒有速度和頻寬限制,永久免費。

  程式碼如下:

<!-- 最新版本的 Bootstrap 核心 CSS 檔案 -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">


<!-- 可選的 Bootstrap 主題檔案(一般不用引入) -->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap-theme.min.css" integrity="sha384-rHyoN1iRsVXV4nD0JutlnGaslCJuC7uwjduW9SVrLvRYooPp2bWYgmgJQIXwl/Sp" crossorigin="anonymous">


<!-- 最新的 Bootstrap 核心 JavaScript 檔案 -->
<script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js" integrity="sha384-Tc5IQib027qvyjSMfHjOMaLkfuWVxZxUPnCJA7l2mCWNIpG9mGCD8wGNIcPD7Txa" crossorigin="anonymous"></script>

  那所謂的CDN就是通過一個網際網路部署在多個資料中心的大型分散式伺服器系統。瀏覽器可以並行的從CDN下載檔案,不需要從自己的伺服器下載檔案。這些檔案不在同一個域中,不會受瀏覽器的限制(同時只能在一個域下載幾個檔案)。因此下載時不會一個一個排隊。另外CDN會根據使用者的位置和更快的路由速度來選擇伺服器下載檔案。

  優點:節省頻寬,提高網站效能。

 1.4   包含的內容

  基本結構:Bootstrap 提供了一個帶有網格系統,連結樣式,背景的基本結構。

  CSS:Bootstrap 自帶以下特性:全域性的CSS設定,定義基本的HTML元素樣式,可擴充套件的class,以及一個先進的網格系統。

  元件:Bootstrap 包含了十幾個可重用的元件,其中包括以下元件:下拉選單,按鈕組,按鈕下拉選單,導航,導航條,路徑導航,分頁,排版,略縮圖,警告對話方塊,進度條,媒體物件等。

  JavaScript外掛:Bootstrap包含了十幾個自定義的jQuery外掛。其中包括:模式對話方塊,標籤頁,滾動條,彈出框等。

  定製:你可以定製Bootstrap的元件,Less變數 和jQuery外掛來得到自己的版本。

1.5  放在專案中

  我們將下載的Bootstrap-3.3.7 放在Django專案中的static目錄下。我下載的是原始碼版本的。

  其次,Bootstrap外掛全部依賴於jQuery,因此jQuery必須在Bootstrap之前就引入

<!-- jQuery (Bootstrap 的所有 JavaScript 外掛都依賴 jQuery,所以必須放在前邊) -->
<script src="/static/JS/jquery-3.2.1.js"></script>
 
<!-- 載入 Bootstrap 的所有 JavaScript 外掛。你也可以根據需要只載入單個外掛。 -->
<script src="/static/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script>

  

2,在Django中配置Bootstrap內容

2.1 配置settings檔案

  我們開啟Django的settings檔案,在最下面新增配置,用於指定靜態檔案的搜尋目錄。只有指定靜態檔案的存放位置,才能在模板中正確引導他們。

STATIC_URL = '/static/'
 
STATICFILES_DIRS = [
    os.path.join(BASE_DIR, 'static'),
]

  注意:STATIC_URL 和STATICFILES_DIRS 不同,可以說兩者並沒有什麼聯絡。STATIC_URL主要是的是前端的URL搜尋路徑。而STATCIFILES_DIRS 主要是聯絡的後臺靜態檔案的路徑地址。

2.2  建立 base.html 模板

  一個網站要有自己的統一風格和公共部分,可以將這部分內容集中到一個基礎模板 base.html中,現在我們在根目錄下的 template 中建一個 base.html 檔案作為站點的基礎模板。

  在Bootstrap文件中,為我們提供了一個非常簡單而且又實用的基礎模板。我們可以拷貝這段程式碼,然後根據自己的需求對其進行改進即可。

  下面是一個官網最基礎的Bootstrap頁面:

<!DOCTYPE html>
<html lang="zh-CN">
  <head>
    <meta charset="utf-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <!-- 上述3個meta標籤*必須*放在最前面,任何其他內容都*必須*跟隨其後! -->
    <title>Bootstrap 101 Template</title>

    <!-- Bootstrap -->
    <link href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" rel="stylesheet">

    <!-- HTML5 shim 和 Respond.js 是為了讓 IE8 支援 HTML5 元素和媒體查詢(media queries)功能 -->
    <!-- 警告:通過 file:// 協議(就是直接將 html 頁面拖拽到瀏覽器中)訪問頁面時 Respond.js 不起作用 -->
    <!--[if lt IE 9]>
      <script src="https://cdn.jsdelivr.net/npm/html5shiv@3.7.3/dist/html5shiv.min.js"></script>
      <script src="https://cdn.jsdelivr.net/npm/respond.js@1.4.2/dest/respond.min.js"></script>
    <![endif]-->
  </head>
  <body>
    <h1>你好,世界!</h1>

    <!-- jQuery (Bootstrap 的所有 JavaScript 外掛都依賴 jQuery,所以必須放在前邊) -->
    <script src="https://cdn.jsdelivr.net/npm/jquery@1.12.4/dist/jquery.min.js"></script>
    <!-- 載入 Bootstrap 的所有 JavaScript 外掛。你也可以根據需要只載入單個外掛。 -->
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/js/bootstrap.min.js"></script>
  </body>
</html>

  然後我們修改部分內容,如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>

    <link rel="stylesheet" href="/static/CSS/home_site.css">
    <link rel="stylesheet" href="/static/theme/{{ blog.theme }}">
    <link rel="stylesheet" href="/static/CSS/article_detail.css">
    <link rel="stylesheet" href="/static/CSS/index.css">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/dist/css/bootstrap.css">
    <script src="/static/JS/jquery-3.2.1.min.js"></script>

</head>
<body>

<div class="header">
    <div class="content">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="/cn_backend/" class="backend">管理</a>
        </p>
    </div>
</div>


<div class="container">
    <div class="row">
        <div class="col-md-3 menu">
             {% load my_tags %}
             {% get_classification_style username %}
        </div>
        <div class="col-md-9">
            {% block content %}

            {% endblock %}
        </div>
    </div>
</div>

</body>
</html>

  

  • 如果需要引入靜態檔案的話,我們需要在模板中要加上 {% load staticfiles %} 之後,才可使用 {% static 'path' %} 引用靜態檔案。
  • HTML語法中,所有的內容都被標籤包裹;標籤及標籤中的屬性可以對內容進行排印、解釋說明等作用。
  • <head></head>標籤內包含網頁的後設資料,是不會在頁面內顯示出來的。<body></body>標籤內才是網頁會顯示的內容。
  • 留意Bootstrap的css、js檔案分別是如何引入的
  • jquery.js 要在 bootstrap.js 前引入。**

 2.3  改寫article_detail.html內容

  這裡我們以article_detail.html為例進行改寫,其他的就不一一列舉。

  我們可以檢視其部分樣式如下:

  我們可以留意 {% block content  %} 是如何與 base.html 進行對應起來的。

完整程式碼如下:

{% extends "base.html" %}


{% block content %}
    {% csrf_token %}
    <div class="article_info">
        <h3 class="text-center title">{{ article_obj.title }}</h3>
        <div class="cont">
            {{ article_obj.content|safe }}
        </div>

        <div class="clearfix">
            <div id="div_digg">
                <div class="diggit action">
                    <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
                </div>
                <div class="buryit action">
                    <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span>
                </div>
                <div class="clear"></div>
                <div class="diggword" id="digg_tips" style="color: red;"></div>
            </div>
        </div>

        <div class="comments list-group">
            <p class="tree_btn">評論樹</p>
            <div class="comment_tree">


            </div>

            <script>

                 $.ajax({
                        url: "/get_comment_tree/",
                        type: "get",
                        data: {
                            article_id: "{{ article_obj.pk }}"
                        },
                        success: function (comment_list) {
                            console.log(comment_list);

                            $.each(comment_list, function (index, comment_object) {

                                var pk = comment_object.pk;
                                var content = comment_object.content;
                                var parent_comment_id = comment_object.parent_comment_id;
                                var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span></div>';

                                if (!parent_comment_id) {

                                    $(".comment_tree").append(s);
                                } else {

                                    $("[comment_id=" + parent_comment_id + "]").append(s);
                                }
                            })

                        }
                    })

            </script>


            <p>評論列表</p>

            <ul class="list-group comment_list">

                {% for comment in comment_list %}
                    <li class="list-group-item">
                        <div>
                            <a href=""># {{ forloop.counter }}樓</a>   
                            <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>  
                            <a href=""><span>{{ comment.user.username }}</span></a>
                            <a class="pull-right reply_btn" username="{{ comment.user.username }}"
                               comment_pk="{{ comment.pk }}">回覆</a>
                        </div>

                        {% if comment.parent_comment_id %}
                            <div class="pid_info well">
                                <p>
                                    {{ comment.parent_comment.user.username }}: {{ comment.parent_comment.content }}
                                </p>
                            </div>
                        {% endif %}

                        <div class="comment_con">
                            <p>{{ comment.content }}</p>
                        </div>

                    </li>
                {% endfor %}


            </ul>

            <p>發表評論</p>
            <p>暱稱:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                         value="{{ request.user.username }}">
            </p>
            <p>評論內容:</p>
            <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
            <p>
                <button class="btn btn-default comment_btn">提交評論</button>
            </p>
        </div>
        <script>
            // 點贊請求
            $("#div_digg .action").click(function () {
                var is_up = $(this).hasClass("diggit");


                $obj = $(this).children("span");

                $.ajax({
                    url: "/digg/",
                    type: "post",
                    data: {
                        "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                        "is_up": is_up,
                        "article_id": "{{ article_obj.pk }}",
                    },
                    success: function (data) {
                        console.log(data);

                        if (data.state) {
                            var val = parseInt($obj.text());
                            $obj.text(val + 1);
                        }
                        else {
                            var val = data.handled ? "您已經推薦過!" : "您已經反對過!";
                            $("#digg_tips").html(val);

                            setTimeout(function () {
                                $("#digg_tips").html("")
                            }, 1000)

                        }

                    }
                })

            });

            // 評論請求
            var pid = "";

            $(".comment_btn").click(function () {

                var content = $("#comment_content").val();

                if (pid) {
                    var index = content.indexOf("\n");
                    content = content.slice(index + 1)
                }


                $.ajax({
                    url: "/comment/",
                    type: "post",
                    data: {
                        "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                        "article_id": "{{ article_obj.pk }}",
                        "content": content,
                        pid: pid
                    },
                    success: function (data) {

                        console.log(data);

                        var create_time = data.create_time;
                        var username = data.username;
                        var content = data.content;

                        var s = `
                           <li class="list-group-item">
                              <div>

                                  <span>${create_time}</span>  
                                  <a href=""><span>${username}</span></a>

                              </div>
                              <div class="comment_con">
                                  <p>${content}</p>
                              </div>

                            </li>`;

                        $("ul.comment_list").append(s);

                        // 清空評論框
                        pid = "",
                                $("#comment_content").val("");

                    }
                })


            });

            // 回覆按鈕事件

            $(".reply_btn").click(function () {

                $('#comment_content').focus();
                var val = "@" + $(this).attr("username") + "\n";
                $('#comment_content').val(val);


                pid = $(this).attr("comment_pk");


            })
        </script>

    </div>
{% endblock %}

  

2.4  其中過程捋一捋

  • 當我們通過url訪問list.html時,頂部的{% extends "base.html" %}告訴Django:“這個檔案是繼承base.html的,你去呼叫它吧。”
  • 於是Django就老老實實去渲染base.html檔案:
  • (如果存在的話,不存在忽略這一步)其中的{% include 'header.html' %}表明這裡需要加入header.html的內容。
  • (如果存在的話,不存在忽略這一步){% include 'footer.html' %}加入footer.html的內容。
  • {% block content %}{% endblock content %}表明這裡應該加入list.html中的對應塊的內容。

 2.5  執行伺服器

  當我們按部就班的完成的所有流程,我們儲存內容,執行開發伺服器,可以在瀏覽器輸入正確的URL地址,就能看到漂亮的頁面。

  展示一下,我做的一個簡單的部落格home頁面

 

3,BBS+Blog部落格系統首頁模板語言的編寫

3.1  設計部落格系統首頁——導航區域

   導航條是我們的應用或者網站中作為導航頁頭的響應式基礎元件。他們在移動裝置上可以摺疊(並且可關可開),且再視口(viewport)寬度增加時逐漸變為水平展開模式。

  我們可以看到我的部落格頁面右上角,如果登入進去的話,如下:

  如果沒有登入的話,則顯示的是下面這樣的狀態: 

  那麼如何寫一個差不多樣式呢? 這裡為了簡單方便起見,我們使用Bootstrap的導航條程式碼。地址:請點我

<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">Brand</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">Link <span class="sr-only">(current)</span></a></li>
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">One more separated link</a></li>
          </ul>
        </li>
      </ul>
      <form class="navbar-form navbar-left">
        <div class="form-group">
          <input type="text" class="form-control" placeholder="Search">
        </div>
        <button type="submit" class="btn btn-default">Submit</button>
      </form>
      <ul class="nav navbar-nav navbar-right">
        <li><a href="#">Link</a></li>
        <li class="dropdown">
          <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
          <ul class="dropdown-menu">
            <li><a href="#">Action</a></li>
            <li><a href="#">Another action</a></li>
            <li><a href="#">Something else here</a></li>
            <li role="separator" class="divider"></li>
            <li><a href="#">Separated link</a></li>
          </ul>
        </li>
      </ul>
    </div><!-- /.navbar-collapse -->
  </div><!-- /.container-fluid -->
</nav>

  那上面程式碼顯示出來的前端頁面如下:

  我們將不需要的東西可以去掉,留下我們需要的,然後修改其中的語言。我們可以去Bootstrap中找到一個小人

   然後新增到 index.html的模板中,最後修改得到如下效果:

 

 

3.2  設計部落格系統首頁——主體佈局

  當首頁的導航區域設計完後,我們開始對主體佈局,然後對尾部佈局,這裡簡單起見,我們不打算寫尾部佈局。

  我們打算將主頁分為三部分,第一部分是目錄區域,中間是程式碼,第三部分是廣告欄區域。

  我們這裡主要學習第二部分內容的填充,所以我們將第一部分和第三部分用進度條表示。

  第一部分和第三部分進度條的程式碼如下:

<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">程式碼</div>
        <div class="col-md-3">
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
    </div>
</div>

  效果如下:

3.3  設計部落格系統首頁——文章列表渲染

  那下面主要的任務就是文章列表的渲染,也就是中間的主要內容,包括文章的內容,點贊功能,評論功能。那主要功能就參考部落格園首頁,我隨便擷取了兩篇部落格,效果如下:

  那這就是主體內容,主要分為部落格題目,部落格博主圖片部落格索引,和博主名稱,釋出於,加上如期,加上評論,閱讀。

  我們就按照這樣的樣式寫即可,只不過把閱讀變為點贊,因為後面我們要實現這樣的效果。

  所以我們這裡主要分為兩部分,一個是上面內容包括文章題目,頭像,索引內容渲染,一個是下面,某某博主發表於什麼時間,點贊,評論。

3.3.1  文章題目,頭像,索引內容渲染

   index.html

<div class="col-md-6">
            <div class="article_list">
                {% for article in article_list %}
                    <div class="article-item">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div class="article-desc">
                            <span class="media-left">
                                <a href=""><img height="56" width="56" src="media/{{ article.user.avatar }}" alt=""></a>
                            </span>
                            <span class="media-right">
                                {{ article.desc }}
                            </span>
                        </div>
                    </div>
                        <hr>
                {% endfor %}
            </div>
        </div>

  views.py

def index(request):

    article_list = models.Article.objects.all()

    return render(request, 'index.html', locals())

  前端頁面展示:

 

3.3.2  文章點贊,評論渲染

  那大體效果做好後,我們可以完成文章點贊,評論的效果。

 程式碼如下:

<div class="small pub_info">
    <span><a href="">{{ article.user.username }}</a> </span>    
    <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>

  我們可以去bootstrap中下載兩個效果圖,一個是評論,一個是點贊,下面是我隨便選擇的兩個樣式。

 

   最後做出來的效果如下:

 

 3.4  設計部落格系統首頁的完整程式碼展示

  程式碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/CSS/index.css">
    <link rel="stylesheet" href="/static/bootstrap-3.3.7/dist/css/bootstrap.css">
    <script rel="stylesheet" src="/static/JS/jquery-3.2.1.js"></script>
    <script rel="stylesheet" src="/static/bootstrap-3.3.7/dist/js/bootstrap.min.js"></script>

</head>
<body>
<nav class="navbar navbar-default">
  <div class="container-fluid">
    <!-- Brand and toggle get grouped for better mobile display -->
    <div class="navbar-header">
      <button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
        <span class="sr-only">Toggle navigation</span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
        <span class="icon-bar"></span>
      </button>
      <a class="navbar-brand" href="#">部落格園</a>
    </div>

    <!-- Collect the nav links, forms, and other content for toggling -->
    <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
      <ul class="nav navbar-nav">
        <li class="active"><a href="#">隨筆<span class="sr-only">(current)</span></a></li>
        <li><a href="#">新聞</a></li>
        <li><a href="#">博文</a></li>

      </ul>

      <ul class="nav navbar-nav navbar-right">
          {% if request.user.is_authenticated %}
              <li><a href="#"><span id="user_icon" class="glyphicon glyphicon-user"></span>{{ request.user.username }}</a></li>
              <li class="dropdown">
              <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">Dropdown <span class="caret"></span></a>
              <ul class="dropdown-menu">
                    <li><a href="#">修改密碼</a></li>
                    <li><a href="#">修改頭像</a></li>
                    <li><a href="/logout/">登出</a></li>
                    <li role="separator" class="divider"></li>
                    <li><a href="#">Separated link</a></li>
              </ul>
            </li>
          {% else %}
              <li><a href="/login/">登入</a> </li>
              <li><a href="/register/">註冊</a> </li>
          {% endif %}
      </ul>
    </div>
  </div>
</nav>

<div class="container-fluid">
    <div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-info">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-danger">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
        <div class="col-md-6">
            <div class="article_list">
                {% for article in article_list %}
                    <div class="article-item">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div class="article-desc">
                            <span class="media-left">
                                <a href=""><img height="56" width="56" src="media/{{ article.user.avatar }}" alt=""></a>
                            </span>
                            <span class="media-right">
                                {{ article.desc }}
                            </span>
                        </div>
                        <div class="small pub_info">
                            <span><a href="">{{ article.user.username }}</a> </span>    
                            <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>
        <div class="col-md-3">
            <div class="panel panel-default">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
            <div class="panel panel-primary">
                <div class="panel-heading">Panel heading without title</div>
                <div class="panel-body">
                    Panel content
                </div>
            </div>
        </div>
    </div>
</div>

</body>
</html>

  

4,BBS+Blog部落格系統個人站點頁面模板語言的編寫

4.1 個人站點頁面的規劃佈局

  那個人站點頁面的話,我們希望做成和部落格園差不多的效果,首先我們檢視我的部落格站點:

   那我們也設定成類似的效果,有一個標題和設定,而我左邊欄目設定為類似於部落格園這種,我的標籤,隨筆分類,隨機歸檔就夠了。希望簡單容易。

  上面的標題也不設定這種一張背景,前面加點字這種,設定成

4.2 個人站點頁面的渲染布局——標題欄設定

  標題欄目我們就簡單的設定為部落格的名稱和設定即可。

  home_site.html的程式碼如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <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: #ffffff;
            margin-left: 15px;
            margin-top: -10px;
        }
        .backend{
            float: right;
            color: #ffffff;
            font-size: 16px;
            margin-right: 14px;
            margin-top: 10px;
            text-decoration: none;

        }
    </style>

</head>
<body>

<div class="header">
    <div class="contents">
        <p class="title">
            <span>{{ blog.title }}</span>
            <a href="" class="backend">管理</a>
        </p>
    </div>
</div>

</body>
</html>

  檢視如下:

4.3  個人站點頁面的渲染布局——左邊標籤欄設定

  左邊標籤欄我們打算設定為我的標籤,隨筆分類,隨機歸檔就OK了。

   程式碼如下:

<div class="row">
        <div class="col-md-3">
            <div class="panel panel-warning">
                <div class="panel-heading">我的標籤</div>
                <div class="panel-body">
                    {% for tag in tag_list %}
                        <p>{{ tag.0 }}({{ tag.1 }})</p>
                    {% endfor %}
                </div>
            </div>

            <div class="panel panel-danger">
                <div class="panel-heading">隨筆分類</div>
                <div class="panel-body">
                    {% for cate in cate_list %}
                        <p>{{ cate.0 }}({{ cate.1 }})</p>
                    {% endfor %}
                </div>
            </div>

            <div class="panel panel-success">
                <div class="panel-heading">隨筆歸檔</div>
                <div class="panel-body">
                    {% for data in data_list %}
                        <p>{{ data.0 }}({{ data.1 }})</p>
                    {% endfor %}
                </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 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>
    </div>

  展示效果如下:

4.4  個人站點頁面的完整程式碼及其效果展示

  index.html程式碼如下:

{% extends 'base.html' %}


{% block content %}
 <div class="article_list">
    {% for article in article_list %}
        <div class="article-item clearfix">
            <h5><a href="/{{ article.user.username }}/articles/{{ article.pk }}">{{ 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>
{% endblock %}

  效果如下:

 

5  Django框架中的自定義模板標籤(template.Library())

  由於用了繼承,會傳相同引數導致程式碼複用,所以某一些標籤(例如:選單欄,css,js,以及一些複雜計算後的資料等)需要我們自定義。然後在指定的HTML中引用並顯示。之所以要用到標籤,主要作用就是想讓一些內容在多個模板(HTML)中都要有,比如選單欄。

  我們絕對不想讓每個檢視函式(views)都寫一次這些變數內容,所以可以繼承一些頁面的共同部分,提取出來搭配 base.html。那麼如何做呢?

5.1  建立register變數

  首先我們在blog這個APP下新建一個名為 templatetags 的資料夾,並在下面建一個名為 my_tags.py的檔案,然後引入template包。其內容如下:

from django import template

#註冊我們自定義的標籤,只有註冊過的標籤,系統才能認識你,這是固定寫法
register = template.Library()

  

5.2  新增自定義標籤,註冊過濾器函式

  由於需求是左邊的欄目會重複使用,其中包括他的引用函式,在views裡面也會重複使用,HTML程式碼也會重複使用。所以我們要是寫了標籤,就不需要重複再寫其程式碼了。

  我們將其檢視函式中的函式和HTML中的重複程式碼提取出來,檢視函式內容如下:

from django import template
from django.db.models import Count
from blog import models

register = template.Library()

@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 {"blog": blog, "cate_list": cate_list, "date_list": date_list, "tag_list": tag_list}

  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>

  

5.3  在 base.html程式碼裡使用上述標籤

  標籤相關方法指的是在html顯示前,後臺先進行預處理,和我們平常的方法相同,只不過這個方法是針對標籤所定義的,,inclution_tag模板語法把引數傳給 inclution_tag 渲染好公共部分後,直接返回 HTML 程式碼會更為方便。

  那 base.html 裡面引用如下:

<div class="container">
    <div class="row">
        <div class="col-md-3 menu">
             {% load my_tags %}
             {% get_classification_style username %}
        </div>
        <div class="col-md-9">
            {% block content %}

            {% endblock %}
        </div>
    </div>
</div>

  我們使用 load  my_tags引用。 

5.4  注意 

 

  標籤字元 [轉義]  才能格式化出文章樣式 safe 後臺必須做一個篩選,否則加上 safe 可能會受到 xss 攻擊。

{% extends 'base.html' %}
{# 繼承公共部分 #}

{% block content %}
    <h3 class="text-center">{{ article_obj.title }}</h3>
    <div class="cont">
        {{ article_obj.content|safe }}
    </div>

{% endblock %}

  

 

相關文章