• Django学习笔记(20)——BBS+Blog项目开发(4)Django如何使用Bootstrap


      本文学习如何通过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("
    ");
                        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") + "
    ";
                    $('#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{
                 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 %}
    

      

     

  • 相关阅读:
    maven错误
    angularjs的一点总结
    工具汇总
    重启outlook的bat脚本
    前端框架参考
    imply套件以及plyql的安装
    centos下nodejs,npm的安装和nodejs的升级
    kafka错误集锦
    动态规划DP笔记
    链接
  • 原文地址:https://www.cnblogs.com/wj-1314/p/10984927.html
Copyright © 2020-2023  润新知