可以使用 CKEditor 编辑器,并在 Django 项目中集成一些工具来支持在文章中间插入和渲染 DOT 语言生成的图形。下面是一个详细的方案,包括步骤、代码示例和一些建议(ECharts也可以):

核心思路:

  1. CKEditor 插件: 创建一个自定义的 CKEditor 插件,用于插入 DOT 代码。
  2. 后端处理: 后端接收文章内容,找到 DOT 代码块,使用 Graphviz 将其渲染为 SVG 或其他格式的图形。
  3. 前端渲染: 将渲染好的图形替换原来的 DOT 代码块,并显示在页面上。

步骤详解:

1. 安装必要的库:

pip install graphviz

安装本地
centos安装

yum install graphviz

注:windows也要装exe软件,去官网下载
详情查看:https://graphviz.org/download/
2. CKEditor 配置和插件创建:

  • 配置 CKEditor: 在你的 settings.py 文件中,确保你已经正确配置了 CKEditor。

    # settings.py
    CKEDITOR_CONFIGS = {
        'default': {
            'toolbar': 'full',  # 或者使用你自定义的工具栏
            'extraPlugins': ['dotblock'],  # 添加自定义插件
        },
    }
  • 创建自定义插件 dotblock

    • 在你的 Django App 的 static 目录下(例如 your_app/static/your_app/ckeditor/plugins)创建以下文件结构:

      your_app/
          static/
              your_app/
                  ckeditor/
                      plugins/
                          dotblock/
                              plugin.js
                              dialogs/
                                  dotblock.js
    • plugin.js 内容:

      CKEDITOR.plugins.add('dotblock', {
          requires: 'dialog',
          icons: 'dotblock',
          init: function (editor) {
              var pluginName = 'dotblock';
              CKEDITOR.dialog.add(pluginName, this.path + 'dialogs/dotblock.js');
      
              editor.addCommand(pluginName, new CKEDITOR.dialogCommand(pluginName));
      
              editor.ui.addButton('dotblock', {
                  label: '插入 Dot 图',
                  command: pluginName,
                  toolbar: 'insert', // 你可以自定义工具栏
                  icon: this.path + 'icons/dotblock.png'
              });
          }
      });
    • your_app/static/your_app/ckeditor/plugins/dotblock目录下 创建icons文件夹,并且放入一个名为 dotblock.png 的图标。你也可以使用其他的图标。

    • dialogs/dotblock.js 内容:

      CKEDITOR.dialog.add('dotblock', function (editor) {
          return {
              title: '插入 Dot 代码',
              minWidth: 400,
              minHeight: 200,
              contents: [
                  {
                      id: 'tab-dot',
                      label: 'Dot 代码',
                      elements: [
                          {
                              type: 'textarea',
                              id: 'dotCode',
                              label: 'DOT 代码',
                              rows: 10,
                              'style': 'width: 100%;'
                          }
                      ]
                  }
              ],
              onOk: function () {
                  var dialog = this;
                  var dotCode = dialog.getValueOf('tab-dot', 'dotCode');
                  var element = editor.document.createElement('pre');
                  element.addClass('dot-code'); // 添加一个类,方便后端识别
                  element.setText(dotCode);
                  editor.insertElement(element);
              }
          };
      });

3. 后端处理 (Django View):

  • 在你的 Django 应用的 views.py 文件中,添加如下函数来处理文章内容:

    from django.shortcuts import render
    from django.http import JsonResponse
    from django.utils.html import format_html
    import graphviz
    import re
    import html
    from django.utils.safestring import mark_safe
    
    def render_dot_in_content(content):
        """
        查找 DOT 代码块,并渲染为 SVG
        """
        def replace_dot(match):
           dot_code = match.group(1).strip()
           try:
               dot_code = html.unescape(dot_code)
               graph = graphviz.Source(dot_code)
               svg_code = graph.pipe(format='svg').decode('utf-8')
                # 移除 xml 头部信息
               svg_code = re.sub(r'<\?xml.*\?>', '', svg_code)
               
               # 将 xlink:href 属性替换为正常的 href 属性, 并且添加 target="_blank"
               svg_code = svg_code.replace('xlink:href="', 'href="').replace('<a ','<a target="_blank" ')
    
               # 使用 mark_safe 标记, 但是不使用 format_html
               return mark_safe(f'<div style="text-align:center;overflow:auto;">{svg_code}</div>')
           
           except Exception as e:
               return f'<pre>Error rendering dot: {e}</pre>'
    
        pattern = r'<pre class="dot-code">(.*?)</pre>'
        rendered_content = re.sub(pattern,replace_dot,content,flags=re.DOTALL)
        return rendered_content
        
    def article_detail(request, article_id):
        # ... 从数据库中获取文章数据 ...
        article = ... # 根据你的数据库操作获取 Article 对象
        content = article.content
        rendered_content = render_dot_in_content(content)
        context = {
           'article': article,
           'content': rendered_content,
        }
    
        return render(request, 'your_app/article_detail.html', context)
  • 在你的 model.py 中,你需要保证 content 是 TextField 或者 RichTextField,可以存储大量的文本数据。

   from django.db import models
   from ckeditor.fields import RichTextField

   class Article(models.Model):
      title = models.CharField(max_length=200)
      content = RichTextField()
      # ... 其他字段 ...

      def __str__(self):
         return self.title

4. 前端渲染 (HTML 模板):

  • 在你的 HTML 模板中 (例如 your_app/article_detail.html),确保你的文章内容被正确渲染:
  ```html
     <!DOCTYPE html>
     <html>
     <head>
         <title>{{ article.title }}</title>
         <style>
          .dot-graph{
              margin:10px 0;
             }
         </style>
     </head>
     <body>
         <h1>{{ article.title }}</h1>
         <div class="article-content">
             {{ content|safe }}
         </div>
     </body>
     </html>
**5\. URL 配置:**

urls.py 中添加对应的 url

 from django.urls import path
 from . import views

 urlpatterns = [
    path('article/<int:article_id>/', views.article_detail, name='article_detail'),
 ]
**解释:**

- **CKEditor 插件:**
    - `plugin.js`: 定义了插件的基本结构,包括图标、命令,以及注册 dialog。
    - `dialogs/dotblock.js`: 创建了一个弹出窗口,让用户可以输入 DOT 代码,并将其包装在带有 `dot-code` 类的 `<pre>` 标签中。
- **后端 (Django):**
    - `render_dot_in_content`: 使用正则表达式找出文章内容中带有 `.dot-code` 类的 `<pre>` 标签,提取 DOT 代码,并使用 `graphviz` 生成 SVG 代码。然后,将 `<pre>` 标签替换为包含 SVG 的 `<div>` 标签。
    - `article_detail`: 从数据库获取文章,调用 `render_dot_in_content` 处理文章内容,然后将渲染后的内容传递给模板。
- **前端 (HTML):**
    - 模板显示文章标题和内容,由于我们在 `views.py` 中已经将 dot 代码转换为了 `SVG` 代码,这里只需要显示即可。

**注意事项:**

- **样式:** 你可能需要添加 CSS 来美化 SVG 图的显示效果。
- **安全性:** 如果你的用户可能输入恶意 DOT 代码,请确保采取适当的安全措施,例如使用沙箱环境来运行 Graphviz。
- **错误处理:** `render_dot_in_content` 中的 `try...except` 块可以帮助你处理无效的 DOT 代码,并显示错误信息,方便调试。
- **扩展:** 你可以根据需要添加其他功能,比如支持自定义图形属性、实时预览等。
- **其他格式:** 你也可以使用其他格式,比如 PNG, JPEG 等。