7. 真正的 django 博客首页视图

本教程内容已过时,更新版教程请访问: Django 博客开发入门教程

这是 Django 博客教程的第 7 篇,在阅读此篇教程以前,请确保你已阅读 Django 博客教程的前 6 篇:
1. Django 博客教程:前言
2. 搭建开发环境
3. 建立我们的 django 博客应用
4. 创建 django 博客的数据库模型
5. 让 django 完成翻译——迁移数据库模型
6. django 博客首页视图

上一节编写了 blog 的首页视图,并且配置了 url,模板,让 django 能够正确地处理 http 请求并返回合适的 http 响应。但是我们仅仅在首页返回了一句话“欢迎访问我的博客”。这只是个 hello world 级别的视图。这一节里我们需要编写真正的首页视图函数,当用户访问我们的博客首页时,他(她)将看到我们发表的博客文章列表,就像演示项目里展示的这样。

上一节我们阐明了 django 的开发流程。首先把 url 和相应的处理函数绑定,一般写在 urls.py 文件里,然后在工程的 urls.py 文件引入。其次是编写我们的视图函数,视图中需要渲染模板,我们也在 settings.py 中进行了模板相关的配置,让 django 能够找到需要渲染的模板。最后把渲染完成的 http 响应返回就可以了。相关的配置和准备工作都在上一节完成了,本节我们只需专心编写视图函数,让它实现我们想要的功能即可。

首页的视图函数其实很简单,代码像这样:

from django.shortcuts import render

from .models import Post


def index(request):
    post_list = Post.objects.all()
    return render(request, 'blog/index.html', context={'post_list': post_list})

我们曾经在前面的章节讲解过模型管理器 objects 的使用。这里我们使用 all() 方法从数据库里获取了全部的文章,存在了 post_list 变量里,然后如前一节所做,我们渲染了 blog/index.html 模板文件,并且把包含文章列表的 post_list 变量传给了模板。

处理 css 与 js文件

我们的项目使用了从网上下载的一套博客模板(点击这里下载全套模板),这里面除了 html 文档外,还包含了一些 css 文件和 js 文件以让网页呈现出我们现在看到的样式。同样我们需要对 django 做一些必要的配置,才能让 django 知道如何在开发服务器中引入这些 css 和 js 文件,这样才能让博客页面的 css 样式生效。

按照惯例,我们把 css 和 js 文件放在 blog 应用的 static 文件夹下。因此,先在 blog 应用下建立一个 static 文件夹。同时,为了避免和其它 app 中的 css 和 js 文件命名冲突,我们再在 static 文件夹下建立一个 blog 文件夹,把下载的文件中的 css 和 js 文件夹连同里面的文件一同拷贝进这个目录。最终我们的 blog 应用目录结构变成了这样:

blog/
    __init__.py
    static/
        blog/
            css/
                .css 文件...
            js/
                .js 文件...
    admin.py
    apps.py
    migrations/
        __init__.py
    models.py
    tests.py
    views.py

用模板中的 index.html 文件替换掉上一节我们自己写的 index.html 文件。如果你好奇,现在就可以运行开发服务器,看看现在的首页是什么样子了。

你会看到首页显示的样式非常混乱,原因是 css 样式文件没有正确加载。需要以 django 的方式来正确地加载 css 和 js 文件。css 样式文件通常在 html 文档的 head 标签里引入,打开 index.html 文件,在文件的开始处找到 head 标签包裹的内容,大概像这样:

<head>
    <title>Black & White</title>

    <!-- meta -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    <!-- css -->
    <link rel="stylesheet" href="css/bootstrap.min.css">
    <link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
    <link rel="stylesheet" href="css/pace.css">
    <link rel="stylesheet" href="css/custom.css">

    <!-- js -->
    <script src="js/jquery-2.1.3.min.js"></script>
    <script src="js/bootstrap.min.js"></script>
    <script src="js/pace.min.js"></script>
    <script src="js/modernizr.custom.js"></script>
</head>

css 样式文件在 link 标签的 href 属性里,而 js 文件在 script 标签的 src 属性里。可以看到诸如 href="css/bootstrap.min.css" 或者 src="js/jquery-2.1.3.min.js" 这样的引用,由于引用文件的路径不对,所以引入失败。我们需要把它们改成正确的路径。把代码改成下面样子,正确地引入 static 文件下的 css 和 js 文件:

<head>
    <title>Black & White</title>

    <!-- meta -->
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">

    + {% load staticfiles %}
    <!-- css -->
    - <link rel="stylesheet" href="css/bootstrap.min.css">
    + <link rel="stylesheet" href="{% static 'blog/css/bootstrap.min.css' %}">
    <link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css">
    - <link rel="stylesheet" href="css/pace.css">
    - <link rel="stylesheet" href="css/custom.css">
    + <link rel="stylesheet" href="{% static 'blog/css/pace.css' %}">
    + <link rel="stylesheet" href="{% static 'blog/css/custom.css' %}">

    <!-- js -->
    - <script src="js/jquery-2.1.3.min.js"></script>
    - <script src="js/bootstrap.min.js"></script>
    - <script src="js/pace.min.js"></script>
    - <script src="js/modernizr.custom.js"></script>
    + <script src="{% static 'blog/js/jquery-2.1.3.min.js' %}"></script>
    + <script src="{% static 'blog/js/bootstrap.min.js' %}"></script>
    + <script src="{% static 'blog/js/pace.min.js' %}"></script>
    + <script src="{% static 'blog/js/modernizr.custom.js' %}"></script>
</head>

我们把引用路径放在了一个奇怪的符号里,例如:href="{% static 'blog/css/bootstrap.min.css' %}"。用 {% %} 包裹起来的叫做模板标签。我们前面说过用 {{ }} 包裹起来的叫做模板变量,其作用是在最终渲染的模板里显示由视图函数传过来的变量的值。而这里我们使用的模板标签的功能则类似于函数,例如这里的 static 模板标签,它把跟在它后面的字符串 'css/bootstrap.min.css' 转换成正确的文件引入路径。这样 css 和 js 文件才能被正确加载,样式才能正常显示。注意这里有一个标签 <link rel="stylesheet" href="http://code.ionicframework.com/ionicons/2.0.1/css/ionicons.min.css"> 我们没有使用模板标签,因为这里的引用的文件是一个外部文件,不是我们项目里 css 目录下的文件,因此无需使用模板标签。

如果你开发服务器还没关的话(关了就重新运行),刷新首页,这次应该能看到期望的效果了。但目前我们看到的只是模板中预先写好的一些数据(还都是英语的...),我们得让它显示我们从数据库中获取的数据。下面来稍微改造一下模板:

在模板 index.html 中你会找到一系列 article 标签:

...
<article class="post post-1">
  ...
</article>

<article class="post post-2">
  ...
</article>

<article class="post post-3">
  ...
</article>
...

这里面包裹的内容就是显示的文章数据了。我们前面在视图函数 index 里给模板传了一个 post_list 变量,它里面包含着从数据库中取出的文章数据列表。就像 Python 一样,我们可以在模板中循环这个列表,把文章一篇篇循环出来,然后一篇篇显示文章的数据。要在模板中使用循环,需要使用到前面提到的模板标签,这次使用 {% for %} 模板标签。删掉多余的 article 标签,只留下一个 article 标签,然后写下列代码:

...
{% for post in post_list %}
  <article class="post post-1">
    ...
  </article>
{% empty %}
  <div class="no-post">暂时还没有发布的文章!</div>
{% endfor %}
...

可以看到语法和 Python 的 for 循环类似,只是被 {% %} 这样一个模板标签符号包裹着。{% empty %} 的作用是当 post_list 为空,即数据库里没有文章时显示 {% empty %} 下面的内容,最后我们用 {% endfor %} 告诉 django 循环在这里结束了。

现在我们可以在循环体内通过 post 变量访问单篇文章了。分析 article 标签里面的 html 内容,h1 显示的是文章的标题,

<h1 class="entry-title">
    <a href="single.html">Adaptive Vs. Responsive Layouts And Optimal Text Readability</a>
</h1>

我们把标题替换成 post 中的数据

<h1 class="entry-title">
    <a href="single.html">{{ post.title }}</a>
</h1>

这里 post 是 Post 类的一个实例,通过引用它的 title 属性获取 title 的值。注意要把它包裹在模板变量里,因为它最终要被替换成实际的 title 值。

<div class="entry-meta">
    <span class="post-category"><a href="#">Web Design</a></span>

    <span class="post-date"><a href="#"><time class="entry-date"
                                              datetime="2012-11-09T23:15:57+00:00">February 2, 2013</time></a></span>

    <span class="post-author"><a href="#">Albert Einstein</a></span>

    <span class="comments-link"><a href="#">4 Comments</a></span>
</div>

这 4 个 span 标签里分别显示了 分类(category)、文章发布时间、文章作者、评论数。再次替换掉一些数据,由于评论数暂时没法替换,因此先留着,我们在实现了评论功能后再来修改它:

<div class="entry-meta">
    <span class="post-category">
      <a href="#">{{ post.category.name }} </a>
    </span>

    <span class="post-date">
      <a href="#">
        <time class="entry-date" datetime="{{ post.created_time }}">{{ post.created_time }}         </time>
      </a>
    </span>

    <span class="post-author"><a href="#">{{ post.author }} </a></span>

    <span class="comments-link"><a href="#">4 Comments</a></span>
</div>
<div class="entry-content clearfix">
    <p>...</p>
    <div class="read-more cl-effect-14">
        <a href="#" class="more-link">Continue reading <span class="meta-nav">→</span></a>
    </div>
</div>

这里 p 标签里显示的是摘要,替换成 post 的摘要,另外 Continue reading 表示继续阅读,汉化一下:

<div class="entry-content clearfix">
    <p>{{ post.excerpt }}</p>
    <div class="read-more cl-effect-14">
        <a href="#" class="more-link">继续阅读 <span class="meta-nav">→</span></a>
    </div>
</div>

再次访问首页,它显示:暂时还没有发布的文章!好吧,做了这么多工作,但是数据库中其实还没有任何数据呀。下一节我们就实际写几篇文章保存到数据库里,看看显示的效果究竟如何。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 207,113评论 6 481
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,644评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,340评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,449评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,445评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,166评论 1 284
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,442评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,105评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,601评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,066评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,161评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,792评论 4 323
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,351评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,352评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,584评论 1 261
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,618评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,916评论 2 344

推荐阅读更多精彩内容