第 11 篇:自動生成文章摘要
作者:HelloGitHub-追夢人物
文中涉及的示例程式碼,已同步更新到 HelloGitHub-Team 倉庫
部落格文章的模型有一個 excerpt
欄位,這個欄位用於儲存文章的摘要。目前為止,還只能在 django admin 後臺手動為文章輸入摘要。每次手動輸入摘要比較麻煩,對有些文章來說,只要摘取正文的前 N 個字元作為摘要,以便提供文章預覽就可以了。因此我們來實現如果文章沒有輸入摘要,則自動摘取正文的前 N 個字元作為摘要,這有兩種實現方法。
覆寫 save 方法
第一種方法是通過覆寫模型的 save
方法,從正文欄位摘取前 N 個字元儲存到摘要欄位。在 創作後臺開啟,請開始你的表演 中我們提到過 save
回顧一下部落格文章模型程式碼:
blog/models.py class Post(models.Model): # 其它欄位... body = models.TextField() excerpt = models.CharField(max_length=200, blank=True) def save(self, *args, **kwargs): self.modified_time = timezone.now() super().save(*args, **kwargs)
其中 body
欄位儲存的是正文,excerpt
欄位用於儲存摘要。通過覆寫模型的 save 方法,在資料被儲存到資料庫前,先從 body
欄位摘取 N 個字元儲存到 excerpt
欄位中,從而實現自動摘要的目的。具體程式碼如下:
blog/models.py import markdown from django.utils.html import strip_tags class Post(models.Model): # 其它欄位... body = models.TextField() excerpt = models.CharField(max_length=200, blank=True) # 其它方法... def save(self, *args, **kwargs): self.modified_time = timezone.now() # 首先例項化一個 Markdown 類,用於渲染 body 的文字。 # 由於摘要並不需要生成文章目錄,所以去掉了目錄拓展。 md = markdown.Markdown(extensions=[ 'markdown.extensions.extra', 'markdown.extensions.codehilite', ]) # 先將 Markdown 文字渲染成 HTML 文字 # strip_tags 去掉 HTML 文字的全部 HTML 標籤 # 從文字摘取前 54 個字元賦給 excerpt self.excerpt = strip_tags(md.convert(self.body))[:54] super().save(*args, **kwargs)
這裡生成摘要的方案是,先將 body
中的 Markdown 文字轉為 HTML 文字,去掉 HTML 文本里的 HTML 標籤,然後摘取文字的前 54 個字元作為摘要。去掉 HTML 標籤的目的是防止前 54 個字元中存在塊級 HTML 標籤而使得摘要格式比較難看。可以看到很多網站都採用這樣一種生成摘要的方式。
然後在模板中適當的地方使用模板標籤引用 {{ post.excerpt }}
顯示摘要的值即可:
templates/blog/index.html
<article class="post post-{{ post.pk }}">
...
<div class="entry-content clearfix">
<p>{{ post.excerpt }}...</p>
<div class="read-more cl-effect-14">
<a href="{{ post.get_absolute_url }}" class="more-link">繼續閱讀 <span class="meta-nav">→</span></a>
</div>
</div>
</article>
新新增一篇文章(這樣才能觸發 save 方法,此前新增的文章不會自動生成摘要,要手動儲存一下觸發 save 方法),可以看到摘要效果了。
使用 truncatechars 模板過濾器
第二種方法是使用 truncatechars
模板過濾器(Filter)。在 django 的模板系統中,模板過濾器的使用語法為 {{ var | filter: arg }}
。可以將模板過濾看做一個函式,它會作用於被它過濾的模板變數,從而改變模板變數的值。例如這裡的 truncatechars
過濾器可以擷取模板變數值的前 N 個字元顯示。關於模板過濾器,我們之前使用過 safe
過濾器,可以參考 讓部落格支援 Markdown 語法和程式碼高亮 這篇文章中對模板過濾器的說明。
例如摘要效果,需要顯示 post.body
的前 54 的字元,那麼可以在模板中使用 {{ post.body | truncatechars:54 }}
。
templates/blog/index.html
<article class="post post-{{ post.pk }}">
...
<div class="entry-content clearfix">
<p>{{ post.body|truncatechars:54 }}</p>
<div class="read-more cl-effect-14">
<a href="{{ post.get_absolute_url }}" class="more-link">繼續閱讀 <span class="meta-nav">→</span></a>
</div>
</div>
</article>
不過這種方法的一個缺點就是如果前 54 個字元含有塊級 HTML 元素標籤的話(比如一段程式碼塊),會使摘要比較難看。所以推薦使用第一種方法。
歡迎關注 HelloGitHub 公眾號,獲取更多開源專案的資料和內