# 前言

本專案選擇 martor 作為後台的文章內文 Markdown 編輯器,比 ckeditor 更輕量化且支援 Markdown 語法,還有提供預覽、支援圖片上傳...功能等功能

# martor 編輯器套件設定

安裝套件

pip install martor

然後在 settings.py 進行基本設定

# settings.py

INSTALLED_APPS = [
    # ...
    'martor',
    # ...
]

# Martor 配置
MARTOR_ENABLE_CONFIGS = {
    'emoji': 'true',
    'imgur': 'true',
    'mention': 'false',
    'jquery': 'true',
    'living': 'false',
    'spellcheck': 'false',
    'hljs': 'true',
}
MARTOR_UPLOAD_URL = '/api/uploader/'  # 圖片上傳 API URL

並在 urls.py 中添加此編輯器的路由

# backend/urls.py
from django.urls import path, include

urlpatterns = [
    # ...
    path('martor/', include('martor.urls')),
    # ...
]

然後修改 Post 模型的 content 欄位,將 TextField 改為 MartorField,並且 migrate 到資料庫

# api/blog/models.py
from martor.models import MartorField

class Post(models.Model):
    """文章模型"""
    ...
    content = MartorField(verbose_name="內容")

此時到後台去看,應就能看到原本的 TextField 變成編輯器了

martor

# 後端

要成功讓 前端渲染 Markdown 內容,後端必須要有一個 API 來提供 Markdown 的內容,這邊使用 Django REST Framework (DRF) 來提供

# 解析並新增 Markdown 欄位

安裝 Python 的 Markdown 解析庫

pip install markdown

# serializer

PostDetailSerializer 中添加一個方法或函數來返回轉換後的 HTML 內容,為防止 XSS 攻擊,使用 bleach 套件來清理輸出的 HTML:

class PostDetailSerializer(serializers.ModelSerializer):
    content_html = serializers.SerializerMethodField()

    ...
    def get_content_html(self, obj):
        """返回 Markdown 轉換後的 HTML 內容"""
        html = markdown.markdown(
            obj.content,
            extensions=['extra', 'codehilite', 'toc']
        )
        # 安全處理 HTML
        allowed_tags = [
            'a', 'abbr', 'acronym', 'b', 'blockquote', 'code', 'em', 'i', 'li', 'ol',
            'pre', 'strong', 'ul', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6', 'p', 'img',
            'table', 'thead', 'tbody', 'tr', 'th', 'td', 'span', 'div'
        ]
        allowed_attrs = {
            'a': ['href', 'title', 'target'],
            'img': ['src', 'alt', 'title', 'width', 'height'],
            'code': ['class'],
            'pre': ['class'],
            '*': ['class']  # 允許所有元素有 class 屬性,用於樣式
        }
        return bleach.clean(html, tags=allowed_tags, attributes=allowed_attrs)

# 前端

要在前端成功渲染 Markdown 內容,就必須自己寫各個標籤的 CSS,但這邊不用這麼麻煩,剛好 tailwind 就有大神做出

tailwindcss-typography,針對 Markdown 內容或從 CMS 中提取的 HTML)添加漂亮且對應的樣式,這邊下載直接使用就好

安裝指令

npm install -D @tailwindcss/typography

然後到專案的主 CSS 配置檔案中,添加:

plugin "@tailwindcss/typography";

最後在內文套用 prose 類別即可,並將 post.content 改為抓 post.content_html,這樣就能成功渲染 Markdown 內容了

// pages/blog/blog-detail-page.js
...
<article className='prose lg:prose-xl max-w-none mb-10' dangerouslySetInnerHTML=<!--swig0--> />

# 結論

  1. 後端:原始 Markdown 內容存儲在資料庫中
  2. API:返回原始 Markdown 內容和轉換後的 HTML
  3. 前端:使用 Tailwind Typography 樣式渲染 HTML 內容

成果:

markdown_result