Django + Markdown实现文章编辑及渲染


在Web开发中,文章编辑与展示是许多平台(如博客、论坛、知识库)的核心功能。传统的富文本编辑器往往存在以下问题:

  • 格式兼容问题:不同编辑器生成的HTML代码差异大,易导致前端渲染混乱
  • 使用门槛高:复杂的工具栏让普通用户难以快速上手
  • 代码展示难题:对程序员而言,无法优雅地展示代码块及语法高亮
  • 迁移维护麻烦:纯HTML存储的内容不利于后期修改和平台迁移

而Markdown作为一种轻量级标记语言,凭借简洁的语法、跨平台兼容、专注内容创作等特性,成为技术类内容创作的首选格式。

本文正是为解决上述问题而编写——通过在Django框架中集成Markdown功能,实现从后台编辑到前端渲染的完整流程,让开发者能够快速搭建一个支持Markdown语法的文章系统,同时兼顾编辑效率与展示效果。无论是个人博客还是企业内容平台,都能通过这套方案获得简洁高效的内容创作体验。

1.后台实现markdown编辑文本

1. 安装django-mdeditor依赖

pip install django-mdeditor

2. 配置settings.py

INSTALLED_APPS = [
    ...
    'mdeditor',  # 添加 mdeditor
    ...
]

...

# MDEditor 配置
MDEDITOR_CONFIGS = {
    'default': {
        'width': '90% ',  # 编辑器宽度
        'height': 500,  # 编辑器高度
        'toolbar': ["undo", "redo", "|",
                    "bold", "del", "italic", "quote", "ucwords", "uppercase", "lowercase", "|",
                    "h1", "h2", "h3", "h5", "h6", "|",
                    "list-ul", "list-ol", "hr", "|",
                    "link", "reference-link", "image", "code", "preformatted-text", "code-block", "table", "datetime",
                    "emoji", "html-entities", "pagebreak", "goto-line", "|",
                    "help", "info",
                    "||", "preview", "watch", "fullscreen"],  # 工具栏
        'upload_image_formats': ["jpg", "jpeg", "png", "gif", "bmp", "webp"],  # 上传图片格式
        'image_floder': 'editor',  # 上传图片存储路径
        'theme': 'default',  # 编辑框主题 dark / default
        'preview_theme': 'default',  # 预览区域主题 dark / default
        'editor_theme': 'default',  # 编辑区域主题 pastel-on-dark / default
        'toolbar_autofixed': True,  # 工具栏是否固定
        'search_replace': True,  # 是否开启查找替换
        'emoji': True,  # 是否开启表情功能
        'tex': True,  # 是否开启 tex 公式功能
        'flow_chart': True,  # 是否开启流程图功能
        'sequence': True,  # 是否开启序列图功能
        'watch': True,  # 实时预览
        'lineWrapping': False,  # 自动换行
        'lineNumbers': False  # 行号
    }
}

3. 配置 URL 路由

urlpatterns = [
    ...
    path('mdeditor/', include('mdeditor.urls')),  # 添加 mdeditor 路由
]

4. 修改模型

class Article(models.Model):
    ...
    # 文章内容字段
    content = MDTextField()  # 使用 MDTextField
    ...

5. 数据库迁移

python manage.py makemigrations
python manage.py migrate

效果展示:

2. 前端渲染数据

models.py文件中,为article模型添加一个formatted_markdown()函数把后台编辑的markdown内容转换成HTML并返回

class Article(models.Model):
    # 文章标题
    title = models.CharField(max_length=100)
    # 文章内容
    content = MDTextField()  # 使用 MDTextField

    def formatted_markdown(self):
        """将 Markdown 内容转换为 HTML"""
        return mark_safe(markdown(self.content, extensions=[
            'markdown.extensions.extra',  # 包含表格、围栏代码等扩展
            'markdown.extensions.codehilite',  # 代码高亮
            'markdown.extensions.toc',  # 目录生成
        ]))

前端页面中导入语法高亮样式

<!-- 引入代码高亮样式 -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/styles/default.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.7.0/highlight.min.js"></script>
<script>hljs.highlightAll();</script>

初始化代码高亮后,调用函数渲染文章内容

<script>
    document.addEventListener('DOMContentLoaded', (event) => {
        // 初始化代码高亮
        hljs.highlightAll();
</script>
<p>{{ article.formatted_markdown|safe }}</p>

效果展示:

3. 个性化设置

前端数据的渲染实际上是把后台的markdown格式的内容有转换成的HTML的形式,如果要对前端渲染的数据进行一些个性化的调整可以把对应元素的样式进行调整,以下是一些示例:

创建markdownstyle.css文件如下:

/* 标题样式 */
h1 {
  padding-bottom: 0.3em;
  border-bottom: 2px solid #eaecef;
  color: #2c3e50;
}

h2 {
  padding-bottom: 0.3em;
  border-bottom: 1px solid #eaecef;
  color: #34495e;
}

/* 代码块样式 */
pre code{
    width: 600px;
    font-size: 17px;
}

/* 表格样式 */
table {
  border-collapse: collapse;
  width: 100%;
  margin: 20px 0;
  box-shadow: 0 1px 3px rgba(0,0,0,0.1);
  border-radius: 6px;
  overflow: hidden;
}

th {
  background-color: #f5f7fa;
  padding: 12px 15px;
  text-align: left;
  font-weight: 600;
  border-bottom: 2px solid #e1e4e8;
  color: #2c3e50;
}

td {
  padding: 10px 15px;
  border-bottom: 1px solid #eaecef;
}

tr:hover {
  background-color: #f6f8fa;
}

/* 链接样式 */
a {
  color: #3498db;
  text-decoration: none;
  transition: all 0.2s ease;
  border-bottom: 1px solid rgba(52, 152, 219, 0.3);
  padding-bottom: 1px;
}

/* 引用块样式 */
blockquote {
  border-left: 4px solid #3498db;
  padding: 0 1em;
  color: #7f8c8d;
  margin-left: 0;
  background-color: #f8f9fa;
  border-radius: 0 6px 6px 0;
  padding: 15px 20px;
}

/* 列表样式 */
ul, ol {
  padding-left: 2em;
  margin: 15px 0;
}

li {
  margin-bottom: 8px;
}


/* 分割线 */
hr {
  height: 1px;
  background-color: #e1e4e8;
  border: none;
  margin: 24px 0;
}

/* 图片 */
img{
    width: 500px;
}

渲染数学公式可以引入KaTeX

<!-- 引入 KaTeX 显示数学公式-->
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.css" integrity="sha384-n8MVd4RsNIU0tAv4ct0nTaAbDJwPJzDEaqSD1odI+WdtXRGWt2kTvGFasHpSy3SV" crossorigin="anonymous">
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/katex.min.js" integrity="sha384-XjKyOOlGwcjNTAIQHIpgOno0Hl1YQqzUOEleOLALmuqehneUG+vnGctmUb0ZY0l8" crossorigin="anonymous"></script>
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.9/dist/contrib/auto-render.min.js" integrity="sha384-+VBxd3r6XgURycqtZ117nYw44OOcIax56Z4dCRWbxyPt0Koah1uHoK0o4+/RRE05" crossorigin="anonymous"></script>

引入后需要进行初始化:

<script>
    document.addEventListener('DOMContentLoaded', (event) => {
        // 初始化 KaTeX
        renderMathInElement(document.body, {
            delimiters: [
                {left: '$$', right: '$$', display: true},
                {left: '$', right: '$', display: false},
            ]
        });
    });
</script>

效果展示:

4. 测试文章

# 测试文档示例

## 1. 文档说明
本文档仅作为markdown格式测试使用,包含多种常见的markdown元素,用于验证排版效果。

## 2. 文本格式示例
- **加粗文本**:这是一段加粗的文字
- *斜体文本*:这是一段斜体的文字
- ***加粗斜体文本***:这是一段加粗且斜体的文字
- ~~删除线文本~~:这是一段带有删除线的文字
- `代码片段`:这是一个单行代码片段示例

## 3. 列表示例

### 3.1 有序列表
1. 第一步操作
2. 第二步操作
3. 第三步操作
   1. 子步骤一
   2. 子步骤二

### 3.2 无序列表
- 项目一
- 项目二
- 项目三
  - 子项目A
  - 子项目B

## 4. 表格示例

| 姓名 | 年龄 | 职业   |
|------|------|--------|
| 张三 | 25   | 工程师 |
| 李四 | 30   | 设计师 |
| 王五 | 35   | 产品经理 |

## 5. 代码块示例
python代码块
```python
# 这是一个Python代码示例
def hello_world():
    print("Hello, World!")

if __name__ == "__main__":
    hello_world()
```
html代码块
```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>hello world</title>
</head>
<body>
    <h1>hello world</h1>
</body>
</html>
```
## 6. 引用示例
> 这是一段引用文本,通常用于引用他人的话语或重要观点。
> 引用内容可以有多行。

## 7. 链接与图片示例
- [百度首页](https://www.baidu.com)
- 图片示例:

  ![](https://ts1.tc.mm.bing.net/th/id/R-C.53fba3d65249ccbab201fd5696320054?rik=z8L7AKQNd9P83Q&riu=http%3a%2f%2fimg95.699pic.com%2fphoto%2f50059%2f8720.jpg_wh860.jpg&ehk=BmsdXItPnaU3qFXzGZR8Ht%2fWacwtI4BeCmgTMy9qQRI%3d&risl=&pid=ImgRaw&r=0)

## 8. 分割线
---

## 9. 任务列表
- [x] 已完成任务1
- [x] 已完成任务2
- [ ] 未完成任务1
- [ ] 未完成任务2

## 10. 数学公式示例
使用LaTeX格式:
$\sum_{i=1}^n i = \frac{n(n+1)}{2}$

行内公式示例:$a^2 + b^2 = c^2$

块状公式示例:
$$
\int_0^\infty e^{-x^2} dx = \frac{\sqrt{\pi}}{2}
$$

5. 源代码

Github

0 条评论

发表评论

暂无评论,欢迎发表您的观点!