在此之前我们已经编写了 Blog 的首页视图,并且配置了 URL 和模板,让 Django 能够正确地处理 HTTP 请求并返回合适的 HTTP 响应。不过仅仅在首页返回了一句话:访问我的第一个博客首页。这是个 Hello World 级别的视图函数,我们需要编写真正的首页视图函数,当用户访问博客首页时,他将看到我们发表的博客文章列表。
首页视图函数
上一节阐明了 Django 的开发流程。即首先配置 URL,把 URL 和相应的视图函数绑定,一般写在 urls.py 文件里,然后在工程的 urls.py 文件引入。其次是编写视图函数,视图中需要渲染模板,我们也在 settings.py 中进行了模板相关的配置,让 Django 能够找到需要渲染的模板。最后把渲染完成的 HTTP 响应返回就可以了。相关的配置和准备工作都在之前完成了,这里只需专心编写视图函数,让它实现我们想要的功能即可。
首页的视图函数其实很简单,代码像这样:
在前面讲解过模型管理器objects的使用。这里使用all()方法从数据库里获取了全部的文章,存在了post_list变量里。all方法返回的是一个QuerySet(可以理解成一个类似于列表的数据结构),由于通常来说博客文章列表是按文章发表时间倒序排列的,即最新的文章排在最前面,所以紧接着调用了order_by方法对这个返回的 queryset 进行排序。排序依据的字段是created_time,即文章的创建时间。-号表示逆序,如果不加-则是正序。 接着如之前所做,渲染了 blog\index.html 模板文件,并且把包含文章列表数据的post_list变量传给了模板。
处理静态文件
项目使用了从网上下载的一套博客模板,这里面除了 HTML 文档外,还包含了一些 CSS 文件和 JavaScript 文件以让网页呈现出我们现在看到的样式。同样需要对 Django 做一些必要的配置,才能让 Django 知道如何在开发服务器中引入这些 CSS 和 JavaScript 文件,这样才能让博客页面的 CSS 样式生效。
按照惯例,把 CSS 和 JavaScript 文件放在blog 应用的 static\ 目录下。因此,先在blog 应用下建立一个 static 文件夹。同时,为了避免和其它应用中的 CSS 和 JavaScript 文件命名冲突(别的应用下也可能有和 blog 应用下同名的 CSS 、JavaScript 文件),我们再在 static\ 目录下建立一个 blog 文件夹,把下载的博客模板中的 css 和 js 文件夹连同里面的全部文件一同拷贝进这个目录。最终我们的 blog 应用目录结构应该是这样的:
用下载的博客模板中的 index.html 文件替换掉之前我们自己写的 index.html 文件。如果你好奇,现在就可以运行开发服务器,看看首页是什么样子。
如图所示,你会看到首页显示的样式非常混乱,原因是浏览器无法正确加载 CSS 等样式文件。需要以 Django 的方式来正确地处理 CSS 和 JavaScript 等静态文件的加载路径。CSS 样式文件通常在 HTML 文档的 head 标签里引入,打开 index.html 文件,在文件的开始处找到 head 标签包裹的内容,大概像这样:
CSS 样式文件的路径在 link 标签的 href 属性里,而 JavaScript 文件的路径在 script 标签的 src 属性里。可以看到诸如 `href="css/bootstrap.min.css" 或者 src="js/jquery-2.1.3.min.js" 这样的引用,由于引用文件的路径不对,所以浏览器引入这些文件失败。需要把它们改成正确的路径。把代码改成下面样子,正确地引入 static 文件下的 CSS 和 JavaScript 文件:
把引用路径放在了一个奇怪的符号里,例如:href="{% static 'blog/css/bootstrap.min.css' %}"。用 {% %} 包裹起来的叫做模板标签。前面说过用 {{ }} 包裹起来的叫做模板变量,其作用是在最终渲染的模板里显示由视图函数传过来的变量值。而这里使用的模板标签的功能则类似于函数,例如这里的static模板标签,它把跟在后面的字符串'css/bootstrap.min.css'转换成正确的文件引入路径。这样 css 和 js 文件才能被正确加载,样式才能正常显示。
替换完成后你可以刷新页面并看看网页的源代码,看一看 {% static %} 模板标签在页面渲染后究竟被替换成了什么样的值。例如可以看到
正确引入了静态文件后样式显示正常了。
修改模板
目前看到的只是模板中预先填充的一些数据,我们得让它显示从数据库中获取的文章数据。下面来稍微改造一下模板:
在模板 index.html 中你会找到一系列 article 标签:
这里面包裹的内容显示的就是文章数据了。我们前面在视图函数 index 里给模板传了一个post_list变量,它里面包含着从数据库中取出的文章列表数据。就像 Python 一样,可以在模板中循环这个列表,把文章一篇篇循环出来,然后一篇篇显示文章的数据。要在模板中使用循环,需要使用到前面提到的模板标签,这次使用 {% for %} 模板标签。将 index.html 中多余的 article 标签删掉,只留下一个 article 标签,然后写上下列代码:
可以看到语法和 Python 的 for 循环类似,只是被 {% %} 这样一个模板标签符号包裹着。{% empty %} 的作用是当post_list为空,即数据库里没有文章时显示 {% empty %} 下面的内容,最后我们用 {% endfor %} 告诉 Django 循环在这里结束了。
你可能不太理解模板中的post和post_list是什么。post_list是一个QuerySet(类似于一个列表的数据结构),其中每一项都是之前定义在 blog\models.py 中的 Post 类的实例,且每个实例分别对应着数据库中每篇文章的记录。因此我们循环遍历post_list,每一次遍历的结果都保存在post变量里。所以使用模板变量来显示post的属性值。例如这里的{{ post.pk }}(pk 是 primary key 的缩写,即 post 对应于数据库中记录的 id 值,该属性尽管我们没有显示定义,但是 Django 会自动为我们添加)。
现在可以在循环体内通过post变量访问单篇文章的数据了。分析 article 标签里面的 HTML 内容,h1 显示的是文章的标题,把标题替换成post的title属性值。注意要把它包裹在模板变量里,因为它最终要被替换成实际的 title 值。
下面这 5 个 span 标签里分别显示了分类(category)、文章发布时间、文章作者、评论数、阅读量。再次替换掉一些数据,由于评论数和阅读量暂时没法替换,因此先留着,我们在之后实现了这些功能后再来修改它,目前只替换分类、文章发布时间、文章作者:
这里 p 标签里显示的是摘要,替换成post的摘要:
再次访问首页,它显示:暂时还没有发布的文章!做了这么多工作,但是数据库中其实还没有任何数据呀!接下来就实际写几篇文章保存到数据库里,看看显示的效果究竟如何。