开启Django博客的RSS功能的实现方法


Posted in Python onFebruary 17, 2020

作者:HelloGitHub-追梦人物 

文中所涉及的示例代码,已同步更新到 HelloGitHub-Team 仓库

博客提供 RSS 订阅应该是标配,这样读者就可以通过一些聚合阅读工具订阅你的博客,时时查看是否有文章更新,而不必每次都跳转到博客上来查看。现在我们就来为博客添加 RSS 订阅功能。

RSS 简介

RSS(Really Simple Syndication)是一种描述和同步网站内容的格式,它采用 XML 作为内容传递的格式。简单来说就是网站可以把内容包装成符合 RSS 标准的 XML 格式文档。一旦网站内容符合一个统一的规范,那么人们就可以开发一种读取这种规范化的 XML 文档的工具来聚合各大网站的内容。例如一个读者可能关注了很多的博客网站,如果这些博客网站都支持 RSS 订阅的话,他就只需要一个聚合阅读器订阅这些博客,就可以在聚合器工具里看到全部博客的更新内容,而不必再分别访问各个博客去看有没有内容更新了。更多 RSS 的介绍,可参考rss (简易信息聚合)。

使用 Django Feed 类

根据以上对 RSS 的介绍,我们可以发现关键的地方就是根据网站的内容生成规范化的 XML 文档,幸运的是,Django 已经内置了一些生成这个文档的方法,下面就使用这些方法来创建 RSS 订阅文档。

首先我们在 blog 应用的根目录下(models.py 所在目录)新建一个 feeds.py 文件以存放和 RSS 功能相关的代码。让后在 feeds.py 中写入如下代码:

blog/feeds.py

from django.contrib.syndication.views import Feed

from .models import Post


class AllPostsRssFeed(Feed):
  # 显示在聚合阅读器上的标题
  title = "HelloDjango-blog-tutorial"

  # 通过聚合阅读器跳转到网站的地址
  link = "/"

  # 显示在聚合阅读器上的描述信息
  description = "HelloDjango-blog-tutorial 全部文章"

  # 需要显示的内容条目
  def items(self):
    return Post.objects.all()

  # 聚合器中显示的内容条目的标题
  def item_title(self, item):
    return "[%s] %s" % (item.category, item.title)

  # 聚合器中显示的内容条目的描述
  def item_description(self, item):
    return item.body_html

代码应该不难理解,主要就是指定要生成的 XML 文档内容。各个属性和方法的含义已在代码中注释,你只需把相关的内容替换成符合你博客的描述即可。

需要注意一点的是这个方法:

# 聚合器中显示的内容条目的描述
  def item_description(self, item):
    return item.body_html

item 是文章 (Post 模型的实例),聚合内容的描述我们返回了 body_html 属性的值。模型中原本使用 body 属性存储博客文章的内容,但是这些内容是以 Markdown 格式的,并非所有的聚合内容阅读器都支持 Markdown 格式的解析,因此我们返回的是已经解析后的 HTML 格式内容。

但 Post 模型原来并没有 body_html 这个属性的,那它是哪里来的呢?

回顾一下 PostDetailView 这个视图,我们在获取博客文章 post 的详细内容的视图中,使用 markdown 这个 Python 库在解析 post.body 这个属性的值。这个解析的过程其实在很多地方都可能用到,不应该写死在 PostDetailView 这个视图里,所以我们先将 PostDetailView 视图的 get_object 方法解析 Markdown 内容的过程封装为一个函数,暂且将其放在 blog/models.py 中。

blog/models.py

def generate_rich_content(value):
  md = markdown.Markdown(
    extensions=[
      "markdown.extensions.extra",
      "markdown.extensions.codehilite",
      # 记得在顶部引入 TocExtension 和 slugify
      TocExtension(slugify=slugify),
    ]
  )
  content = md.convert(value)
  m = re.search(r'<div class="toc">\s*<ul>(.*)</ul>\s*</div>', md.toc, re.S)
  toc = m.group(1) if m is not None else ""
  return {"content": content, "toc": toc}

解析过程和原来一样,只是将解析得到的 HTML 内容(content)和目录(toc)放在一个字典里返回。

然后,我们来给 Post 模型定义几个属性,以便方便地获取解析后的内容和目录:

blog/models.py

from django.utils.functional import cached_property

class Post(models.Model):
  # 省略其它代码
  
  @property
  def toc(self):
    return self.rich_content.get("toc", "")

  @property
  def body_html(self):
    return self.rich_content.get("content", "")

  @cached_property
  def rich_content(self):
    return generate_rich_content(self.body)

首先看到 rich_content 这个方法,它返回的是 generate_rich_content 函数调用后的结果,即将 body 属性的值经 Markdown 解析后的内容。但要注意的是我们使用了 django 提供的 cached_property 装饰器,这个装饰器和 Python 内置的 property 装饰器功能一样,可以将方法转为属性,这样就能够以属性访问的方式获取方法返回的值,不过 cached_property 进一步提供缓存功能,它将被装饰方法调用返回的值缓存起来,下次访问时将直接读取缓存内容,而不需重复执行方法获取返回结果。例如对博客文章内容的 Markdown 解析是比较耗时的,而解析的结果可能被多次访问,因此将其缓存起来能起到优化作用。

为了更方便地获取文章的 HTML 格式的内容和目录,我们进一步将 generate_rich_content 返回的值放到 toc 和 body_html 两个属性中,这里两个属性都从 rich_content 中取值,cached_property 的作用就发挥出来了。

添加 URL

接下来就是指定 URL 模式,让人们访问这个 URL 后就可以看到 Feed 生成的内容。通常 RSS 的 URL 配置直接写在项目的 urls.py 文件里,即打开 blogproject/urls.py 文件,添加如下代码:

blogproject/urls.py

from blog.feeds import AllPostsRssFeed

urlpatterns = [
  path('admin/', admin.site.urls),
  path('', include('blog.urls')),
  path('', include('comments.urls')),

  # 记得在顶部引入 AllPostsRssFeed
  path('all/rss/', AllPostsRssFeed(), name='rss'),
]

修改模板

简单修改一下 templates/base.html 模板,把 RSS 的 URL 添加到模板中:

<div class="rss">
  <a href="{% url 'rss' %}" rel="external nofollow" ><span class="ion-social-rss-outline"></span> RSS 订阅</a>
</div>

此外,由于将 Markdown 解析的内容放在了 body_html 属性,将之前博客文章详情模板里获取文章内容的代码也做相应调整:

templates/blog/detail.html

<div class="entry-content clearfix">
  {{ post.body_html|safe }}
</div>

运行开发服务器,在侧边栏点击 RSS 订阅的链接,就跳转到 /all/rss/,你会看到这对乱码一样的东西,这就是生成的 RSS 标准文档,当然这个文档不是给你读的,而是给 RSS 聚合阅读器工具读的。

RSS 测试插件

可以在本地测试一下订阅效果,我使用的 Chrome 浏览器,安装了一个 RSS Feed Reader 的应用,如果你也使用的 Chrome 浏览器,可以从应用商店添加它,然后就可以在本地测试订阅效果了。如果是其它浏览器,自行查找相关 RSS 阅读插件即可。我本地测试效果如下:

开启Django博客的RSS功能的实现方法

可以看到订阅成功了,订阅界面显示的信息就是我们在 AllPostsRssFeed 类中指定的相关信息。大功告成,现在任何人都可以订阅我们的博客了!

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python中MySQL数据迁移到MongoDB脚本的方法
Apr 28 Python
Python自动化测试ConfigParser模块读写配置文件
Aug 15 Python
python如何使用正则表达式的前向、后向搜索及前向搜索否定模式详解
Nov 08 Python
Python使用django框架实现多人在线匿名聊天的小程序
Nov 29 Python
Python使用SQLite和Excel操作进行数据分析
Jan 20 Python
详谈在flask中使用jsonify和json.dumps的区别
Mar 26 Python
无法使用pip命令安装python第三方库的原因及解决方法
Jun 12 Python
Python 存储字符串时节省空间的方法
Apr 23 Python
Python3.5常见内置方法参数用法实例详解
Apr 29 Python
PyQt5显示GIF图片的方法
Jun 17 Python
python实现将列表中各个值快速赋值给多个变量
Apr 02 Python
Python 输出详细的异常信息(traceback)方式
Apr 08 Python
Python3打包exe代码2种方法实例解析
Feb 17 #Python
Django 博客实现简单的全文搜索的示例代码
Feb 17 #Python
Python使用qrcode二维码库生成二维码方法详解
Feb 17 #Python
django2.2 和 PyMySQL版本兼容问题
Feb 17 #Python
基于python3的socket聊天编程
Feb 17 #Python
python词云库wordCloud使用方法详解(解决中文乱码)
Feb 17 #Python
python词云库wordcloud的使用方法与实例详解
Feb 17 #Python
You might like
PHP5中虚函数的实现方法分享
2011/04/20 PHP
php制作动态随机验证码
2015/02/12 PHP
javascript使用activex控件的代码
2011/01/27 Javascript
Javascript selection的兼容性写法介绍
2013/12/20 Javascript
JavaScript数组深拷贝和浅拷贝的两种方法
2014/04/16 Javascript
用javascript读取xml文件读取节点数据
2014/08/12 Javascript
JS中获取函数调用链所有参数的方法
2015/05/07 Javascript
jQuery根据元素值删除数组元素的方法
2015/06/24 Javascript
关于JavaScript的变量的数据类型的判断方法
2015/08/14 Javascript
jQuery fancybox在ie浏览器下无法显示关闭按钮的解决办法
2016/02/19 Javascript
探讨Vue.js的组件和模板
2017/10/27 Javascript
js实现GIF图片的分解和合成
2019/10/24 Javascript
JavaScript中reduce()的5个基本用法示例
2020/07/19 Javascript
[00:43]魔廷新尊——痛苦女王至宝捆绑包
2020/06/12 DOTA
Python中的闭包详细介绍和实例
2014/11/21 Python
python私有属性和方法实例分析
2015/01/15 Python
python中查看变量内存地址的方法
2015/05/05 Python
浅谈Python peewee 使用经验
2017/10/20 Python
你眼中的Python大牛 应该都有这份书单
2017/10/31 Python
python如何使用正则表达式的前向、后向搜索及前向搜索否定模式详解
2017/11/08 Python
解决Pycharm中import时无法识别自己写的程序方法
2018/05/18 Python
详解python中的hashlib模块的使用
2019/04/22 Python
Python多版本开发环境管理工具介绍
2019/07/03 Python
Django获取该数据的上一条和下一条方法
2019/08/12 Python
PyTorch中Tensor的拼接与拆分的实现
2019/08/18 Python
python数据库开发之MongoDB安装及Python3操作MongoDB数据库详细方法与实例
2020/03/18 Python
Pandas读取csv时如何设置列名
2020/06/02 Python
详解Python中的Lock和Rlock
2021/01/26 Python
Skyscanner澳大利亚:全球领先的旅游搜索网站
2018/03/24 全球购物
传承焦裕禄精神思想汇报2014
2014/09/10 职场文书
镇副书记专题民主生活会对照检查材料思想汇报
2014/10/02 职场文书
内乡县衙导游词
2015/02/05 职场文书
全国法制宣传日活动总结
2015/05/05 职场文书
社区低保工作总结2015
2015/07/23 职场文书
淡雅古典唯美少女娇媚宁静迷人写真
2022/03/21 杂记
Windows Server 版本 20H2 于 8 月 9 日停止支持,Win10 版本 21H1 将于 12 月结束支
2022/07/23 数码科技