前言:
本章中,我们开始引入前端框架Bootstrap 来美化界面。在前面的章节中,我们通过编写后端代码来处理数据。数据之于网站,就相当于灵魂之于人类。而网站的前端就相当于人的形体外貌。其中HTML是骨架,而CSS是皮肤,JavaScript就是肢体动作,可以用来展示数据,处理跟用户的交互行为。
上面的说法稍稍有点感性,对于技术人员来说,比较好理解的说法是JavaScript是编程语言,跟Python没有太大的区别,只是执行环境不同,处理的目标不同。从语言本质上来说,这两种语言都是动态语言,有很多通用的地方,两者也在相互借鉴发展。
而HTML和CSS的逻辑性就稍稍弱了一些,相对来说更像是配置。写一段代码后你会发现里面没有逻辑处理的部分,基本上就是编写结构,配置结构要展示的样式,这些都是固定内容,所以我个人觉得,相对于编写JavaScript来说,HTML和CSS更多靠经验。很多东西如果你用过或者知道,就可以实现,反之,很难写出来。
有了上面的一些认识,我们看看网上关于HTML和CSS的定义。
HTML
超文本标记语言(英语:HyperText Markup Language,简称:HTML)是一种用于创建网页的标准标记语言。HTML 是一种基础技术,常与CSS、JavaScript 一起被众多网站用于设计令人赏心悦目的网页、网页应用程序以及移动应用程序的用户界面。网页浏览器可以读取HTML文件,并将其渲染成可视化网页。HTML 描述了一个网站的结构及其对应的呈现,这使之成为一种标记语言而非编程语言。
参考:https://developer.mozilla.org/zh-CN/docs/Web/HTML
CSS
层叠样式表(Cascading Style Sheet,常缩写为CSS),是一种样式表语言,用来描述HTML 或 XML(包括SVG、XHTML之类的XML分支语言)文档的呈现。CSS 描述了在屏幕、纸质、音频等其他媒体上的元素应该如何被渲染。
对于Web开发程序员来说,能够编写简单的页面是十分必要的。在这一章中,我们就通过Bootstrap 这个CSS框架来认识前端的这些东西,也美化一下我们的界面。
即便在各种前端框架繁荣发展的今天,Bootstrap的易用性和前人大量的实践分享都是我们选择它的原因。
不过需要说明的是,对于公司中开发对外发布的系统时,前端的样式基本上都是自己设计并开发的,不会用现成的CSS框架。
第五章:引入前端样式框架Bootstrap
5.1 Bootstrap 的基本用法
在正式修改项目代码之前,我们先根据之前设计的页面样式(虽然有点简陋)做一个静态页面。这也是正式开发中常见的流程,由前端组/部门来做静态页面,完成之后交给后端,后端来套页面。
5.1.1 介绍
我们先来了解Bootstrap 是什么。Bootstrap发展到现在,其实已经不能够用CSS框架来概括了,因为它提供了很多除页面布局之外的功能,封装了很多常用的交互组件。因此,这个框架中除了有CSS之外,还有JavaScript代码。这些功能在日常开发中会经常用到。
Bootstrap之所以能够流行起来,最大的原因还是它的易用性好。虽然不如专门的设计师设计之后再经过前端工程师做处理的页面更符合自己的业务需求,但对于没有设计师和前端工程师资源的人来说,已经比自己画的页面好看很多了。尤其是对于很多不太能熟练应用前端技术的Web后端开发人员来说,Bootstrap 能够让你通过简单的配置得到一个看起来比较美观的页面。不得不说,这极大地提高了后端开发人员的开发能力。
我们先看看这个框架能够提供什么功能,从大的分类上来说包含以下几个。
- **页面脚手架:**比如样式重置、浏览器兼容、栅格系统和简单布局。
- **基础的CSS样式:**比如代码高亮、排版、表单、表格和一些小的样式效果。
- **组件:**提供了很多常用组件,如tab、pill、导航、弹窗、顶部栏和card等。
- JavaScript插件: 主要是一些动态功能,比如下拉菜单、模态窗口和进度条等。
5.1.2 容器和栅格系统
容器和栅格系统需要单独拿出来说,这是我们需要用到的基础部分。
- **容器:**就是在定义元素时增加 container的class,比如
<div class="container"></div>
,这样就可以放置通过Bootstrap定义好的其他块。容器有两种,一种是固定居中的容器,用来做两侧有留白的页面,这是网站开发中很常见的样式,我们的博客样式也是如此。另外一种是无固定宽度,也就是跟随屏幕宽度布局,这通过设置class属性为container-fluia来实现。这种容器的宽度始终占屏幕的100%。 - **栅格系统:**简单理解就是把页面划分为12列,这样就可以通过我们需要展示的内容占多少列来确定其宽度。比方说,我们定义一个左右分隔的布局:左侧是内容区,占比比较大,我们定义为9列;右侧占比较小,定义为3列。
下面还是通过一个简单的示例来直观地体验一下。
typeidea/templates/blog目录下新建demo.html静态文件,编写如下代码:
html
<!-- demo.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Django实战开发-bootstrap demo</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.min.css" rel="stylesheet" media="screen">
</head>
<body>
<div class="container" style="border: 1px solid red;">
<h1>Hello, world!</h1>
</div>
<div class="container" style="border: 1px solid red;">
<div class="row">
<div class="col-9" style="border: 1px solid blue;">
<div style="height: 500px;">内容区</div>
</div>
<div class="col-3" style="border: 1px solid blue;">
<div style="height: 500px;">边栏区</div>
</div>
</div>
</div>
<footer class="container" style="border: 1px solid red;">
底部footer区域
</footer>
</body>
</html>
这是一个很简陋的页面,直接使用国内的Bootstrap 镜像源,用Bootstrap 的container 和栅格系统做出来的样式。当然,这个样式对于能熟练使用CSS 的人来说,用原生CSS 也能很好实现。但对于不熟悉CSS的后端开发人员来说,通过Bootstrap同样可以很快完成这个布局,并且能够兼容大部分浏览器。
如果你对HTML和CSS不怎么熟悉的话,建议去网上找一下基础入门教程。虽然有些公司的后端开发岗位不怎么要求前端,但是对于程序员来说,需要有能力来解决技术问题,尤其是跟自己主业相关的问题。长远来看,提高自己解决问题的能力是有益的。
实现完上述代码之后,看看效果,接着把所有的container 修改为container-fluid看看,或者也可以看看Bootstrap的官网文档或者中文翻译文档,根据自己的想法来增删元素。相对于编写 Python 或者JavaScript代码,使用Bootstrap设计布局更像是在搭积木。
5.1.3 简单的页面布局
有了一个大概的了解之后,还是通过实践来感受一下具体的用法。这里我们来完成静态博客页面的前端代码编写。先来看一下代码,然后解释其中的部分内容(list.html页面中编写):
html
<!-- list.html -->
<!DOCTYPE HTML>
<html lang="en">
<head>
<title>Typeidea blog - by 不染是非</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
<style>
.post {
margin-bottom: 5px;
}
</style>
</head>
<body>
<div class="container head">
<nav class="navbar fixed-top navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="#">首页</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
<li class="nav-item">
<a class="nav-link" href="#">Python</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Django实战</a>
</li>
<li class="nav-item">
<a class="nav-link" href="#">Tornado</a>
</li>
</ul>
<form class="form-inline my-2 my-lg-0">
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">搜索</button>
</form>
</div>
</nav>
<div class="jumbotron">
<h1 class="display-4">Typeidea</h1>
<p class="lead">基于Django的多人博客系统</p>
</div>
</div>
<div class="container main">
<div class="row">
<div class="col-xl-9 post-list">
<div class="card post">
<div class="card-body">
<h5 class="card-title"><a href="#">这里是标题</a></h5>
<span class="card-link">作者:<a href="#">max</a></span>
<span class="card-link">分类:<a href="#">Python</a></span>
<span class="card-link">标签:
<a href="#">Python</a>
<a href="#">Django</a>
<a href="#">经验</a>
</span>
<p class="card-text">Some quick example text to build on the card title and make
up the bulk of the card's content.<a href="#">完整内容</a></p>
</div>
</div>
<div class="card post">
<div class="card-body">
<h5 class="card-title"><a href="#">这里是标题</a></h5>
<span class="card-link">作者:<a href="#">max</a></span>
<span class="card-link">分类:<a href="#">Python</a></span>
<span class="card-link">标签:
<a href="#">Python</a>
<a href="#">Django</a>
<a href="#">经验</a>
</span>
<p class="card-text">Some quick example text to build on the card title and make
up the bulk of the card's content.<a href="#">完整内容</a></p>
</div>
</div>
<div class="card post">
<div class="card-body">
<h5 class="card-title"><a href="#">这里是标题</a></h5>
<span class="card-link">作者:<a href="#">不染是非</a></span>
<span class="card-link">分类:<a href="#">Python</a></span>
<span class="card-link">标签:
<a href="#">Python</a>
<a href="#">Django</a>
<a href="#">经验</a>
</span>
<p class="card-text">Some quick example text to build on the card title and make up
the bulk of the card's content.<a href="#">完整内容</a></p>
</div>
</div>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
Page {{ page_obj.number }} of {{ page_obj.paginator.num_pages }}.
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
</div>
<div class="col-xl-3">
<div class="card sidebar">
<div class="card-body">
<h4 class="card-title">关于博主</h4>
<p>
网名:不染是非, Python博主
</p>
</div>
</div>
</div>
</div>
<footer class="footer">
<div class="container">
<hr/>
<nav class="nav category">
<a href="#" class="nav-link">读书</a>
<a href="#" class="nav-link">产品</a>
<a href="#" class="nav-link">工作经历</a>
</nav>
</div>
<div class="container power">
<span class="text-muted">Power by Typeidea@不染是非</span>
</div>
</footer>
</div>
</body>
</html>
如果按照本博客敲到电脑的代码没有错误的话,应该能得到下面的效果:

代码看着可能有点多,但是想想上面的话,这其实就是用多种"积木"搭完的"城堡"。我们来挨个了解一下用到的"积木"。
- **container:**提供容器,所有的其他元素需要在此容器中,这在前面介绍过。
- **navbar:**导航栏组件,用来配置导航信息,里面包含很多组件,比如navbar-brand、navbar-nav 和dropdown 等。但是这不重要,对于初学者来说,你只需要知道根据文档定义的格式填上自己的内容,就可以展示对应的样式。这就是"搭积木"逻辑,动手做,观察结果,再次动手操作。
- **jumbotron:**直译为超大屏幕,使用大块的内容来展示重要的信息,比如说博客标题和介绍。
- **row和col-?:**其实就是栅格系统的具体用法,用来排版行和列。对应的列还有col-sm-?以及col-md-?等。命名都很直观,我们用到的col-?就是自动根据页面来分隔的,而col-sm-?的意思为small column,col-md-?的意思为middle column,其他类似。不同的命名方式对应不同的页面最大或者最小宽度。
- **card:**卡片组件,以卡片的方式来组织内容的展示。在上图中,你看到的文章列表部分和侧边栏部分使用的就是卡片组件。
好了,到此为止,你应该对Bootstrap有个简单的认识。如果这是你初次接触前端样式,那么你还需要花点时间看看Bootstrap文档,也看看相关的例子。
5.1.4 总结
如上面所说,有了 Bootstrap 这类前端框架,前端页面的布局就跟搭积木很相似了。但如果你想要使用积木快速搭出漂亮的结果,就需要花点时间来熟悉你有哪些积木,有哪些形状的积木。
因此,还是那句话,别着急看完本书,赶进度本身没意义,你需要做的是每一步都能攻克一个知识点,这样才能不断地往上走。
另外,当你掌握了基础的前端知识之后,就会发现原来每天看到的页面是这么来的。
5.1.5 参考资料
Bootstrap中文文档,v3版:
Bootstrap官方文档:
Bootstrap 国内CDN镜像:
5.2 基于Bootstrap美化页面
上一节简单介绍了Bootstrap的用法,并且快速搭建出一个静态页面。书中关于前端知识的介绍比较少,但是对于一本写Django实战的书,确实没有太多篇幅拿出来给前端,尤其是前端的知识也不是一两章就能够讲完的。因此,对于更完整和系统的前端知识,你需要自己花些时间来学习、反复实践、琢磨和总结。
尽管使用Bootstrap 可以很快做出一个页面,但是我们需要意识到的一点是,CSS、HTML和Bootstrap的关系就像是Python和Django的关系一样。你不能说我精通Django,但是我Python掌握得一般。如果你Python掌握得不够好,那么Django中的很多原理你是无法理解的。我们不能只停留在事物的表面,除了知其然还要知其所以然。
简单使用Bootstrap和Django都没有问题,如果想要深入,那么前提是必须要掌握好CSS、HTML以及Python这样的基础知识。
上一节中,我们完成了简单的静态页面的布局,这一节就来把静态页面套到Django 程序的模板中。这是我们经常干的事。
5.2.1 修改模板
在套页面之前、先来了解 Django 模板的特点。之前也有提到过,Djamgo 模板提供的功能比较简单,只支持简单的变量渲染和条件语句。额外的功能都是通过tag或者filter 来实现的。
这对于套页面来说是个好事。就像Django 自己号称的那样,前端同学也可以参考Django模板的语法编写出Django 能渲染的页面来。
不过对于我们的业务特点来说,不需要自定义tag或者filter,就可以完成模板页面的开发。
套页面时我们需要做的就是把那些重复的东西改为for...in这样的循环语句,把写死的展示内容(比如"这里是标题"等)改为实际的变量渲染。
有了指导思想,接着来改造base.html。如果你觉得下面的代码太多了,那么我建议你根据上一节写的静态页面以及上一章编写的模板内容自己体验一下如何套页面:
html
<!-- base.html -->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}首页{% endblock %}- typeidea博客系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/4.0.0/css/bootstrap.css">
<style>
.post {
margin-bottom: 5px; <!-- 配置每个post卡片下面的间隔 -->
}
</style>
</head>
<body>
<div class="container head">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">首页</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
{% for cate in navs %}
<li class="nav-item">
<a class="nav-link" href="{% url 'category-list' cate.id %}">{{ cate.name }}</a>
</li>
{% endfor %}
</ul>
<form class="form-inline my-2 my-lg-0" method='GET'>
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">搜索</button>
</form>
</div>
</nav>
<div class="jumbotron">
<h1 class="display-4">Typeidea</h1>
<p class="lead">基于Django的多人博客系统</p>
</div>
</div>
<div class="container main">
<div class="row">
<div class="col-9 post-list">
{% block main %}
{% endblock %}
</div>
<div class="col-3">
{% block sidebar %}
{% for sidebar in sidebars %}
<div class="card sidebar">
<div class="card-body">
<h4 class="card-title">{{ sidebar.title }}</h4>
<p>
{{ sidebar.content_html }}
</p>
</div>
</div>
{% endfor %}
{% endblock %}
</div>
</div>
</div>
<footer class="footer">
{% block footer %}
<div class="container">
<hr/>
<nav class="nav category">
{% for cate in categories %}
<a href="{% url 'category-list' cate.id %}" class="nav-link">{{ cate.name }}</a>
{% endfor %}
</nav>
</div>
<div class="container power">
<span class="text-muted">Power by Typeidea@不染是非</span>
</div>
{% endblock %}
</footer>
</body>
</html>
接着编写list.html页面,这个页面的代码就简单多了:
html
<!-- list.html -->
{% extends "blog/base.html" %}
{% block title %}
{% if tag %}
标签页: {{ tag.name }}
{% elif category %}
分类页: {{ category.name }}
{% else %}
首页
{% endif %}
{% endblock %}
{% block main %}
{% for post in post_list %}
<div class="card post">
<div class="card-body">
<h5 class="card-title"><a href="{% url 'post-detail' post.id %}">{{ post.title }}</a></h5>
<span class="card-link">作者:<a href="#">{{ post.owner.username }}</a></span>
<span class="card-link">分类:<a href="{% url 'category-list' post.category_id %}">{{ post.category.name }}</a></span>
<span class="card-link">标签:
{% for tag in post.tag.all %}
<a href="{% url 'tag-list' tag.id %}">{{ tag.name }}</a>
{% endfor %}
</span>
<hr/>
<p class="card-text">{{ post.desc }}<a href="{% url 'post-detail' post.id %}">完整内容</a></p>
</div>
</div>
{% endfor %}
{% if page_obj %}
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">上一页</a>
{% endif %}
Page {{ page_obj.number }} of {{ paginator.num_pages }}.
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一页</a>
{% endif %}
{% endif %}
{% endblock %}
至于最终的detail.html页面,我们只需要稍作修改即可,把分类的部分加上链接,也可以照着分类的样式增加标签或者创建时间等展示字段。
html
<!-- detail.html -->
{% extends "blog/base.html" %}
{% block title %} {{ post.title }} {% endblock %}
{% block main %}
{% if post %}
<h1>{{ post.title }}</h1>
<div>
<span>分类:<a href="{% url 'category-list' post.category_id %}">{{ post.category.name }}</a></span>
<span>作者:<a href="#">{{ post.owner.username }}</a></span>
<span>创建时间:{{ post.created_time }}</span>
</div>
<hr/>
<p>
{{ post.content }}
</p>
{% endif %}
{% endblock %}
如果你是手动敲代码,应该会遇到各种模板错误的提示,比如标签未闭合或者某个字段未定义之类的。不过不要担心,出现这些异常在开发中是正常情况,仔细阅读错误提示,然后解决它。
最终,你可能会发现很多错误都是低级错误,比如说少写了一个endblock标签,某个变量的单词写错了等。
在能正常运行之后,建议你根据自己的喜好进行样式调整,不断地熟悉这些代码。
页面结果展示:


这里说明一下,最上方是分类标签且为导航时才会显示,最新评论和最近更新创建时内容为空,数据会自行显示
5.2.2 总结
写到这里,你应该能够意识到,在编写本章的代码时,我们并没有修改后端的业务代码,基本上都是纯前端页面的修改,通过已知的后端提供的变量来进行渲染。
因此,你可以思考这样一个问题,如果现在需要做单页应用或者做手机客户端的应用,后端需要提供什么内容?
从本质上来说,无论是返回JSON还是HTML,基本上没有什么差别,只是输出格式不同而已。因此,你万不可觉得写API接口是潮流,就绕过了对HTML的学习。
5.3 配置线上静态资源
在前面的章节中,我们只用到了一个 CSS,并且是通过 CDN引用的。那么问题来了,如果需要部署到独立的网络环境中,比如不能访问外网,应该怎么处理。或者为了避免免费CDN的故障给我们带来的损失,应该怎么处理。这一节就来做这件事。
5.3.1 内联CSS和外联CSS
不知道你有没有注意到,在前面两节中有这样一段代码在CSS资源文件的下方:
html
<style>
.post (
margin-bottom: 5px;
</style>
这种CSS的写法叫作内联CSS。一般情况下,CSS样式直接写到HTML中没什么问题,样式展示上没影响,跟通过link标签加载网络资源一样。但在日常开发中,我们会把CSS独立成一个资源文件,而不是直接内联在HTML中。为什么呢?这么做有以下两个好处。
- **便于独立开发,跟页面解耦:**页面渲染上只需要管理资源地址即可。
- **便于版本管理:**不同版本的资源可以通过版本号或者MD5来区分。
你可以想一下,如果使用内联样式,怎么解决上面提到的两个问题。
但是外链的方式也不都是优点,也有对应的缺点,这个缺点对应着内联到HTML中的优点。
我们知道,一次网络请求中,最为耗时的部分就是建立连接,这个耗时占了一个资源(网页或者静态资源)加载的大部分时间。所以我们在进行访问优化时,尽量会减少一个页面中的资源请求数。对于前端开发来说,最常见的莫过于雪碧图(也称sprite,或者精灵图)了,这是一种典型的通过冗余资源来减少网络请求的例子。
所以,在页面访问优化的方案中,有一种就是把关键的CSS样式内联到HTML的头部来优化首屏的展示时间。
不仅仅对于CSS 是如此,对于 JavaScript来说也是如此。只是JavaScript文件一般会放到页面底部加载,不影响页面渲染,所以通常情况下都是独立出来的。
所以说,不能单纯下结论说哪种方式是好的或者坏的,需要根据场景来定。你可以看看经常访问的网站的HTML源码,看看它们是怎么组织CSS资源的。
5.3.2 Django中的静态资源
我们要把外部网络上的CSS资源放到本地,就需要通过Django来提供静态资源服务。那么,怎么在Django中处理静态资源呢?
在开发模式下,Django 提供了静态文件访问的功能,即通过在INSTALLED_APPS中增加'django.contrib.staticfiles'这个App,这是初始化Django项目时默认带上的。
它的作用是帮我们在开发环境中提供静态资源的服务功能,但是仅限于在DEBUG=True的情况下。因为当我们部署到线上时,会把 DBBUG 设置为False 来保证性能和安全。因此,线上静态资源的服务就需要通过其他程序来处理,比如Nginx和CDN等。
在settings文件中,关于静态资源的配置有这么几项(这个也是初始化Django项目时默认带上的):
python
STATIC_URL = 'static/'
关于Django的部分,我们说明一下STATIC的配置。
- **STATIC_ROOT:**用来配置部署之后的静态资源路径。Django提供了collectionstatic命令来收集所有的静态资源到STATIC_ROOT配置的目录中,这样就可以通过Nginx这样的软件来配置静态资源路径了。这里没有用到。
- **STATIC_URL:**用来配置页面上静态资源的起始路径,比如博客列表页中CSS资源拆分之后的地址就是/static/bootstrap.css
- **STATICPILES_DIRS:**用来指定静态资源所在的目录。我们访问上面的CSS 地址时,Django会去这些目录下查找。同时对于上面提到的collectionstatic命令来说,也会去这些目录下查找。这里也没有用到。
5.3.3在模板中使用静态资源
在模板中使用静态资源有几种方式。首先,需要意识到的一点是,静态资源也是通过 HTTP或者HTTPS协议访问到的。常见的静态资源配置有这么几种。
- **http(s): //www.buranshifei.com/static/bootstrap.css:**HTTP或者HTTPS的方式。
- **//www.buranshifei.com/static/bootstrap.css:**相对协议的方式,根据当前页面是哪种方式来定。
- **/static/bootstrap.css:**相对路径,相对于页面的域名。
在Django 的模板中,我们可以使用{%static 'bootstrap.css' %}
这样的方式来配置静态资源。使用 static 标签而不是直接写死为/static/bootstrap.css 的目的就是避免把static 硬编码到页面中,因为这里的static 是依据上面的STATIC_URL='static/得来的。
需要注意的是,代码{%static 'bootstrap.css' %}
中的static 标签并不是Django模板内置的模板标签,需要在模板顶部加载该标签:{% load static %}
。
我们来把Bootstrap的CSS文件改到本地。
首先,在typeidea目录下新建文件夹static,然后下载bootstrap.css到本地的 typeidea/static/目录下(当然,你也可以选择下载bootstrap.min.css,这是压缩后的CSS 文件 )。
** 目录结构如下:**

接着,修改blog/base.html的代码,在文件最上面增加:
html
{% load static %}
** 这是加载静态文件相关的tag。然后就可以使用static关键字来加载静态资源了:**
html
<link rel="stylesheet" href="{% static 'bootstrap.css' %}">
** 把之前引用的外网的静态资源地址改为上面这样即可。**
** 修改后的完整base.html代码如下:**
html
{% load static %} <!-- 修改部分 -->
<!DOCTYPE HTML>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{% block title %}首页{% endblock %}- typeidea博客系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link rel="stylesheet" href="{% static 'bootstrap.css' %}"> <!-- 修改部分 -->
<style>
.post {
margin-bottom: 5px; <!-- 配置每个post卡片下面的间隔 -->
}
</style>
</head>
<body>
<div class="container head">
<nav class="navbar navbar-expand-lg navbar-light bg-light">
<a class="navbar-brand" href="/">首页</a>
<div class="collapse navbar-collapse" id="navbarSupportedContent">
<ul class="navbar-nav mr-auto">
{% for cate in navs %}
<li class="nav-item">
<a class="nav-link" href="{% url 'category-list' cate.id %}">{{ cate.name }}</a>
</li>
{% endfor %}
</ul>
<form class="form-inline my-2 my-lg-0" method='GET'>
<input class="form-control mr-sm-2" type="search" placeholder="Search" aria-label="Search">
<button class="btn btn-outline-success" type="submit">搜索</button>
</form>
</div>
</nav>
<div class="jumbotron">
<h1 class="display-4">Typeidea</h1>
<p class="lead">基于Django的多人博客系统</p>
</div>
</div>
<div class="container main">
<div class="row">
<div class="col-9 post-list">
{% block main %}
{% endblock %}
</div>
<div class="col-3">
{% block sidebar %}
{% for sidebar in sidebars %}
<div class="card sidebar">
<div class="card-body">
<h4 class="card-title">{{ sidebar.title }}</h4>
<p>
{{ sidebar.content_html }}
</p>
</div>
</div>
{% endfor %}
{% endblock %}
</div>
</div>
</div>
<footer class="footer">
{% block footer %}
<div class="container">
<hr/>
<nav class="nav category">
{% for cate in categories %}
<a href="{% url 'category-list' cate.id %}" class="nav-link">{{ cate.name }}</a>
{% endfor %}
</nav>
</div>
<div class="container power">
<span class="text-muted">Power by Typeidea@不染是非</span>
</div>
{% endblock %}
</footer>
</body>
</html>
然后尝试运行一下代码,看看结果(页面打开时速度会变快,其余页面效果跟之前一样)。
这种方式跟我们之前讲到的{%url 'post-detail' post.id %}
方式一样,也是避免硬编码静态文件地址到页面中的一种方式。
5.3.4 总结
到这里,我们就了解了开发环境中静态资源的配置,虽然只是说了CSS文件的配置,但是JavaScript 文件也是一样的,都是静态资源,依次类推即可。
这是开发时的静态资源配置,等最终上线时我们再来具体阐述如何部署线上的静态资源。
5.3.5 参考资料
配置静态文件:
https://docs.djangoproject.com/zh-hans/4.2/howto/static-files//#configuring-static-filesa
5.4 本章总结
在这一章中,我们简单介绍了前端的几个概念以及Bootstrap 提供了哪些功能,最终通过套用Bootstrap框架实现静态页面,完成页面美化工作。