開啓 Django 博客的 RSS 功能

做者:HelloGitHub-追夢人物html

文中所涉及的示例代碼,已同步更新到 HelloGitHub-Team 倉庫python

博客提供 RSS 訂閱應該是標配,這樣讀者就能夠經過一些聚合閱讀工具訂閱你的博客,時時查看是否有文章更新,而沒必要每次都跳轉到博客上來查看。如今咱們就來爲博客添加 RSS 訂閱功能。git

RSS 簡介

RSS(Really Simple Syndication)是一種描述和同步網站內容的格式,它採用 XML 做爲內容傳遞的格式。簡單來講就是網站能夠把內容包裝成符合 RSS 標準的 XML 格式文檔。一旦網站內容符合一個統一的規範,那麼人們就能夠開發一種讀取這種規範化的 XML 文檔的工具來聚合各大網站的內容。例如一個讀者可能關注了不少的博客網站,若是這些博客網站都支持 RSS 訂閱的話,他就只須要一個聚合閱讀器訂閱這些博客,就能夠在聚合器工具裏看到所有博客的更新內容,而沒必要再分別訪問各個博客去看有沒有內容更新了。更多 RSS 的介紹,可參考 rss (簡易信息聚合)github

使用 Django Feed 類

根據以上對 RSS 的介紹,咱們能夠發現關鍵的地方就是根據網站的內容生成規範化的 XML 文檔,幸運的是,Django 已經內置了一些生成這個文檔的方法,下面就使用這些方法來建立 RSS 訂閱文檔。web

首先咱們在 blog 應用的根目錄下(models.py 所在目錄)新建一個 feeds.py 文件以存放和 RSS 功能相關的代碼。讓後在 feeds.py 中寫入以下代碼:chrome

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 文檔內容。各個屬性和方法的含義已在代碼中註釋,你只需把相關的內容替換成符合你博客的描述便可。django

須要注意一點的是這個方法:編程

# 聚合器中顯示的內容條目的描述
    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 返回的值放到 tocbody_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' %}"><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 閱讀插件便可。我本地測試效果以下:

能夠看到訂閱成功了,訂閱界面顯示的信息就是咱們在 AllPostsRssFeed 類中指定的相關信息。大功告成,如今任何人均可以訂閱咱們的博客了!


『講解開源項目系列』——讓對開源項目感興趣的人再也不畏懼、讓開源項目的發起者再也不孤單。跟着咱們的文章,你會發現編程的樂趣、使用和發現參與開源項目如此簡單。歡迎留言聯繫咱們、加入咱們,讓更多人愛上開源、貢獻開源~

相關文章
相關標籤/搜索