HelloDjango 第 09 篇:让博客支持 Markdown 语法和代码高亮

作者:HelloGitHub-追梦人物
文中涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库
为了让博客文章具有良好的排版,显示更加丰富的格式,我们使用 Markdown 语法来书写博文。Markdown 是一种 HTML 文本标记语言,只要遵循它约定的语法格式,Markdown 的解析工具就能够把 Markdown 文档转换为标准的 HTML 文档,从而使文章呈现更加丰富的格式,例如标题、列表、代码块等等 HTML 元素。由于 Markdown 语法简单直观,不用超过 5 分钟就可以轻松掌握常用的标记语法,因此大家青睐使用 Markdown 书写 HTML 文档。下面让我们的博客也支持使用 Markdown 写作。
安装 Python Markdown
将 Markdown 格式的文本解析成标准的 HTML 文档是一个复杂的工程,好在已有好心人帮我们完成了这些工作,直接拿来使用即可。首先安装 Markdown,这是一个 Python 第三方库,在项目根目录下运行命令 pipenv install markdown。
在 detail 视图中解析 Markdown
将 Markdown 格式的文本解析成 HTML 文本非常简单,只需调用这个库的 markdown 方法。我们书写的博客文章内容存在 Post 的 body 属性里,回到我们的详情页视图函数,对 post 的 body 的值做一下解析,把 Markdown 文本转为 HTML 文本再传递给模板:
blog/views.py
import markdown
from django.shortcuts import get_object_or_404, render
from .models import Post
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
post.body = markdown.markdown(post.body,
extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
return render(request, 'blog/detail.html', context={'post': post})
这样我们在模板中显示 {{ post.body }} 的时候,就不再是原始的 Markdown 文本了,而是解析过后的 HTML 文本。注意这里我们给 markdown 解析函数传递了额外的参数 extensions,它是对 Markdown 语法的拓展,这里使用了三个拓展,分别是 extra、codehilite、toc。extra 本身包含很多基础拓展,而 codehilite 是语法高亮拓展,这为后面的实现代码高亮功能提供基础,而 toc 则允许自动生成目录(在以后会介绍)。
来测试一下效果,进入后台,这次我们发布一篇用 Markdown 语法写的测试文章看看,你可以使用以下的 Markdown 测试代码进行测试,也可以自己书写你喜欢的 Markdown 文本。假设你是 Markdown 新手请参考一下这些教程,一定学一下,保证你可以在 5 分钟内掌握常用的语法格式,而以后对你写作受用无穷。可谓充电 5 分钟,通话 2 小时。以下是我学习中的一些参考资料:
# 一级标题
## 二级标题
### 三级标题
- 列表项1
- 列表项2
- 列表项3
> 这是一段引用
```python
def detail(request, pk):
post = get_object_or_404(Post, pk=pk)
post.body = markdown.markdown(post.body,
extensions=[
'markdown.extensions.extra',
'markdown.extensions.codehilite',
'markdown.extensions.toc',
])
return render(request, 'blog/detail.html', context={'post': post})
```
如果你发现无法显示代码块,即代码无法换行,请检查代码块的语法是否书写有误。代码块的语法如上边的测试文本中最后一段所示。
你可能想在文章中插入图片,目前能做的且推荐做的是使用外链引入图片。比如将图片上传到七牛云这样的云存储服务器,然后通过 Markdown 的图片语法将图片引入。Markdown 引入图片的语法为:。
safe 标签
我们在发布的文章详情页没有看到预期的效果,而是类似于一堆乱码一样的 HTML 标签,这些标签本应该在浏览器显示它自身的格式,但是 django 出于安全方面的考虑,任何的 HTML 代码在 django 的模板中都会被转义(即显示原始的 HTML 代码,而不是经浏览器渲染后的格式)。为了解除转义,只需在模板变量后使用 safe 过滤器即可,告诉 django,这段文本是安全的,你什么也不用做。在模板中找到展示博客文章内容的 {{ post.body }} 部分,为其加上 safe 过滤器:{{ post.body|safe }},大功告成,这下看到预期效果了。

safe 是 django 模板系统中的过滤器(Filter),可以简单地把它看成是一种函数,其作用是作用于模板变量,将模板变量的值变为经过滤器处理过后的值。例如这里 {{ post.body|safe }},本来 {{ post.body }}经模板系统渲染后应该显示 body 本身的值,但是在后面加上 safe 过滤器后,渲染的值不再是 body 本身的值,而是由 safe 函数处理后返回的值。过滤器的用法是在模板变量后加一个 | 管道符号,再加上过滤器的名称。可以连续使用多个过滤器,例如 {{ var|filter1|filter2 }}。
代码高亮
程序员写博客免不了要插入一些代码,Markdown 的语法使我们容易地书写代码块,但是目前来说,显示的代码块里的代码没有任何颜色,很不美观,也难以阅读,要是能够像代码编辑器里一样让代码高亮就好了。
代码高亮我们借助 js 插件来实现,其原理就是 js 解析整个 html 页面,然后找到代码块元素,为代码块中的元素添加样式。我们使用的插件叫做 highlight.js 和 highlightjs-line-numbers.js,前者提供基础的代码高亮,后者为代码块添加行号。
首先在 base.html 的 head 标签里引入代码高亮的样式,有多种样式供你选择,这里我们选择 GitHub 主题的样式。样式文件直接通过 CDN 引入,同时在 style 标签里自定义了一点元素样式,使得代码块的显示效果更加完美。
<head>
...
<link href="https://cdn.bootcss.com/highlight.js/9.15.8/styles/github.min.css" rel="stylesheet">
<style>
.codehilite {
padding: 0;
}
/* for block of numbers */
.hljs-ln-numbers {
-webkit-touch-callout: none;
-webkit-user-select: none;
-khtml-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
text-align: center;
color: #ccc;
border-right: 1px solid #CCC;
vertical-align: top;
padding-right: 5px;
}
.hljs-ln-n {
width: 30px;
}
/* for block of code */
.hljs-ln .hljs-ln-code {
padding-left: 10px;
white-space: pre;
}
</style>
</head>
然后是引入 js 文件,因为应该等整个页面加载完,插件再去解析代码块,所以把 js 文件的引入放在 body 底部:
<body>
<script src="https://cdn.bootcss.com/highlight.js/9.15.8/highlight.min.js"></script>
<script src="https://cdn.bootcss.com/highlightjs-line-numbers.js/2.7.0/highlightjs-line-numbers.min.js"></script>
<script>
hljs.initHighlightingOnLoad();
hljs.initLineNumbersOnLoad();
</script>
</body>
非常简单,通过 CDN 引入 highlight.js 和 highlightjs-line-numbers.js,然后初始化了两个插件。再来看下效果,非常完美!


欢迎关注 HelloGitHub 公众号,获取更多开源项目的资料和内容
HelloDjango 第 09 篇:让博客支持 Markdown 语法和代码高亮的更多相关文章
- 写博客常用MarkDown语法
目录 前言 1. 制作目录 2. 命令格式: 3. 超链接 4.上标和下标 5.引用 6.分割线 7.给图片添加图注 参考 前言 自己记性不是很好,导致每次写MarkDown文本时总是忘了一些重要 ...
- [技术博客]React Native——HTML页面代码高亮&数学公式解析
问题起源 原有博文显示时代码无法高亮,白底黑字的视觉效果不好. 原有博文中无法解析数学公式,导致页面会直接显示数学公式源码. 为了解决这两个问题,尝试了一些方法,最终利用开源类库实现了页面美化. (失 ...
- 201771010117—马兴德—实验一 软件工程准备—掌握博客中MarkDown的使用以及通读《现代软件工程—构建之法》的总结
实验一 软件工程的前期准备工作 在前期的准备工作以及老师上课的讲解中,我懂得了"软件=程序+软件工程"这句话的基本含义,以前只是对软件工程有一个很浅显的概念,现在在读了<现代 ...
- Orchard运用 - 为博客启用Markdown编辑器
有时决定你是否使用某一个博客系统,最看重就是如何更简便的写博客,不能让其成为一个负担或别扭费力不讨好的工作. 对此一个好的编辑器就是一个最靓丽的卖点.比如最新的博客系统ghost.org就只定位一个最 ...
- 使用Scribefire在博客中插入语法高亮
效果如下, 文字1 int cool void main() { cout<<"hello world!"<<endl } 文字2 经过一番折腾,终于搞定了 ...
- 博客用Markdown编辑器插入视频
要展示一些App的效果用或者更方便地展示工具的操作,可以使用视频. 以下有两种方式可以在博客中插入视频 第一种 此方法适用于插入来源优酷的视频或者你自己录制了视频上传到优酷,这种方法的好处是可以插入时 ...
- 【Markdown】notepad++ 支持 markdown语法、预览
Notepad++中支持Markdown 最近在学习Markdown语言的使用,很想在XP主机上使用Markdown的离线编辑器,但MarkdownPad.作业部分的离线客户端都不能再XP上运行, ...
- vim 支持 markdown 语法
/************************************************************************* * vim 支持 markdown 语法 * 说明 ...
- sublime 如何安装插件实现高效输入,如何支持markdown 语法,并实时预览
啊,一直想鼓捣markdown的语法,但是配置什么的有点麻烦.不过用起来的话,真心顺手.无需考虑格式与语法点来点去影响效率, 用心去搬砖,用脚修bug 一.初识 Package Control 首先, ...
随机推荐
- 数据库系统概念:JDBC
import java.sql.*; public class DataBase { public static void main() { } } /* 5.1.1 JDBC */ class JD ...
- [Windows无法连接到 System Event Notification Service服务]解决方案
我之前使用Windows的过程的有出现过以下问题,之前因为比较急就匆忙解决了没来得及把解决方法写下来. 正好今天有个朋友电脑也出现此问题过来找我寻求解决方法,便把解决方法写了下来. 电脑出现的问题,如 ...
- 宽度总结-scrollWidth,clientWidth,offectWidth
平时写js的时候,有时候会遇到这样的情况,需要去计算元素或者屏幕的宽度,再进行不同的处理,但是宽度真的有不少,很容易搞混,特此总结下,也希望大家亲测下,这样比较有体会,记得牢固些. 1.scrollW ...
- 个人永久性免费-Excel催化剂功能第59波-快速调用Windows内部常用工具命令
Windows里一些常用的工具.命令,许多存放得很深的位置,不容易找到,每次还要百度半天才能调用成功,Excel催化剂现将常用的操作,提取至插件中完成,一键即可调出相应功能,无需苦苦找寻. 使用场景 ...
- C语言入门8-数组-基本算法
一. 什么是数组 数组就是具有相同数据类型的有序集合. 分为一维数组.二维数组及多维数组. 一维数组就是用一个下标定义的数组 二维数组就是用二个下标定义的数组 我们把具有三个下标及三 ...
- Java_Map接口
Map接口 1.1 Map接口概述 我们通过查看Map接口描述,发现Map接口下的集合与Collection接口下的集合,它们存储数据的形式不同,如下图. Collection中的集合,元素是孤立存在 ...
- cookbook_数据结构和算法
1.1将数据分解为单独的变量 list_a = [1,2,3,4,5,6,7,8,9] a,b,c,d,e,f,g,h,i = list_a print(a,b,c,d,e,f,g,h,i) #使用相 ...
- JSP数据交互(一)
1.JSP内置对象:JSP内置对象是 Web 容器创建的一组对象,不用通过手动new就可以使用 2.JSP9大内置对象: 对象名称 类型 request (请求对象) javax.servl ...
- PHP与ECMAScript_6_常用运算符
优先级从上到下 PHP ECMAScript 特殊运算符 [ ] ,( ) [ ] ,( ) 自增减/类型 ++ -- ! int float string array object @ (错误抑 ...
- Java实现常见的排序算法
一.排序算法 常见的排序算法主要分为下面几类: 选择排序 堆排序 冒泡排序 快速排序 插入排序 希尔排序 归并排序 桶式排序 基数排序 本文主要介绍选择排序.堆排序.冒泡排序.快速排序和归并排序的原理 ...