11. 页面侧边栏

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

这是 Django 博客教程的第 11 篇,在阅读此篇教程以前,请确保你已阅读 Django 博客教程的前 10 篇:
1. Django 博客教程:前言
2. 搭建开发环境
3. 建立我们的 django 博客应用
4. 创建 django 博客的数据库模型
5. 让 django 完成翻译——迁移数据库模型
6. django 博客首页视图
7. 真正的 django 博客首页视图
8. 在 django admin 后台发布我们的文章
9. 博客文章详情页
10. 支持 markdown 语法和代码高亮

我们的博客侧边栏有三项内容:最近发表的博客文章、归档和分类。这些内容相对比较固定,且在各个页面都会显示,如果像文章列表或者文章详情一样,在视图函数中获取然后传递给模板,则每个页面对应的视图函数里都要写一段获取这些内容的代码,然后传递给模板,这会导致很多重复代码。更好的解决方案是直接在模板中获取,为此,我们使用 django 的一个新技术:自定义模板标签来完成我们的任务。

我们接触过一些 django 内置的模板标签,比如比较简单的 {% static %} 模板标签,这个标签帮助我们在模板中引入静态文件。还有比较复杂的如 {% for %} {% endfor%} 标签。这里我们希望自己定义一个模板标签,它可以这样工作:我们只要在模板中写入 {% get_recent_posts as recent_post_list %},那么模板中就会有一个从数据库获取的最近文章列表,并通过 as 语句保存到 recent_post_list 模板变量里,这样我们就可以通过 for 模板标签来循环这个变量,显示文章列表了。这和我们在编写博客首页面视图函数是一样的,它在视图函数中从数据库获取文章列表输入保存到 post_list 变量,并把这个 post_list 变量传给模板,模板使用 for 模板标签循环这个文章列表变量,从而展示一条条文章列表。这里唯一的不同是我们从数据库获取文章列表的操作不是在视图函数中进行,而是在模板中通过我们定义的 get_recent_posts 模板标签进行。

以上就是解决思路,但模板标签不是我们随便乱写的,必须遵循 django 的规范我们才能在模板语言使用我们定义的模板标签,下面我们就依照这些规范来实现我们的需求。

首先在我们的 blog 应用下创建一个 templatetags 文件夹。然后在这个文件夹下创建一个 __init__.py 文件,使这个文件夹变为一个 Python 包,之后在创建一个 blog_tags.py 文件,这个文件存放我们自定义的模板标签的代码。

打开 blog_tags.py 文件,开始写我们的模板标签。模板标签本质上就是一个 Python 函数,比如这里我们的 {% get_recent_posts %},它应该对应着一个函数,这个函数将从数据库获取最近文章列表并返回他们。

templatetags/blog_tags.py

from ..models import Post

def get_recent_posts(num=5):
    return Post.objects.all()[:num]

这个函数的功能是获取数据库中前 num 篇文章,这里 num 默认为 5。函数就这么简单,但目前它还只是一个纯 Python 函数,django 模板还不知道该如何使用它。为了能够通过 {% get_recent_posts %} 在模板中调用这个函数,必须按照 django 的规定注册这个函数为模板标签,方法如下:

templatetags/blog_tags.py

from django import template

from ..models import Post

register = template.Library()


@register.simple_tag
def get_recent_posts(num=5):
    return Post.objects.all()[:num]

这里我们首先导入 template 这个包,然后实例化了一个 template.Library,并将函数装饰为 register.simple_tag。这样就可以在模板中使用语法 {% get_recent_posts %} 调用这个函数了。

如法炮制,实现归档,分类列表。

归档:

templatetags/blog_tags.py

@register.simple_tag
def archives():
    return Post.objects.dates('created_time', 'month', order='DESC')

这个 dates 方法会返回一个列表,列表中的元素为每一篇 Post 创建的时间,精确到月份,降序排列。接受的三个参数值表明了这些含义,一个是 created_time ,即 Post 的创建时间,month 是精度,order='DESC' 表明降序排列。例如如果我们写了 3 篇文章,分别发布于 2017 年 2 月 21 日、2017 年 3 月 25 日、2017 年 3 月 28 日,那么 date 将返回 2017 年 3 月 和 2017 年 2 月这样一个时间列表,从而帮助我们实现按月归档的目的。

分类:

templatetags/blog_tags.py

@register.simple_tag
def get_categories():
    return Category.objects.all()

然后在模板中使用它们:

打开 base.html,为了使用模板标签,我们首先需要在模板中导入它。当时我们为了使用 static 模板标签时曾经导入过 {% load staticfiles %},这次先在最顶部导入 blog_tags:

templates/base.html

{% load blog_tags %}
<!DOCTYPE html>
<html>
...
</html>

然后找到最新文章列表处,把里面的列表修改一下:

<div class="widget widget-recent-posts">
    <h3 class="widget-title">最新文章</h3>
    {% get_recent_posts as recent_post_list %}
    <ul>
        {% for post in recent_post_list %}
        <li>
            <a href="{{ post.get_absolute_url }}">{{ post.title }}</a>
        </li>
        {% endfor %}
    </ul>
</div>

这里我们通过使用 get_recent_posts 模板标签获取到最新文章列表,然后我们通过 as 将获取的文章列表保存进了 recent_post_list 模板变量中,之后就可以通过 for 循环来循环显示了,这和我们在写首页视图时是一样的。

然后是归档部分:

<div class="widget widget-archives">
  <h3 class="widget-title">归档</h3>
  {% archives as date_list %}
  <ul>
    {% for date in date_list %}
    <li>
      <a href="#">{{ date.year }} 年 {{ date.month }} 月</a>
    </li>
    {% endfor %}
  </ul>
</div>

同样,这里我们调用 archives 模板标签获取自动获取一个文章发表的日期列表,精确到月份,然后保存在 date_list 模板变量里。由于日期列表中的元素为 Python 的 date 对象,因此可以通过其 year 和 month 属性分别获取其年和月的信息,<a href="#">{{ date.year }} 年 {{ date.month }} 月</a> 反应了这个事实。

分类部分也一样了:

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

推荐阅读更多精彩内容