1. 程式人生 > 程式設計 >開啟Django部落格的RSS功能的實現方法

開啟Django部落格的RSS功能的實現方法

作者: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')),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 類中指定的相關資訊。大功告成,現在任何人都可以訂閱我們的部落格了!

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支援我們。