在django项目中集成trix编辑器

背景

公司基于 adminset 框架做运维管理系统,需要一个页面来记录有关运维管理系统的基本概念、开发思路及用法。自告奋勇接了开发这个 wiki 模块的活。由于目前需要显示的内容不多,wiki 模块就两个页面,一个编辑 wiki,一个展示内容。

总结

通过这个集成项目,学到的技能有

  1. 熟悉了 django 的 model,view,url,form,templates 流程和用法。

  2. 了解并实现了 Ajax 传递信息。

  3. 了解了 django 文件上传的设置方式。

过程

在页面上编辑文章,需要用到编辑器,不然就是一个多行单元格。

v0.1

  1. 输入页面由一个多行输入框构成,内容中带 markdown 标签,存储入数据库。

  2. 展示页面获取带标签的文章,用解释器解释为正确格式的 html 文档。

使用的插件为 Stack Overflow 上评论用的插件 pagedown 。调试 js 有点绕,看 demo 后成功调用插件。存在的缺点有 1)图片不支持,2)不能所见即所得。有点:存储带标签的文档,可以由不同 markdown 解释器转换为 html。

v0.2

使用trix 编辑器-trix 编辑器 ,此编辑器是 37signals 团队 2018 年 5 月开源的。此团队写了 Ruby on Rails 框架,redo,rework 两本书。
显示页面引入 trix 的 js 和 css 后,直接显示

1
2
3
4
5
6
7
8
9
<head>
<link rel="stylesheet" type="text/css" href="/static/css/trix.css" />
<script type="text/javascript" src="/static/js/trix.js"></script>
</head>
<body>
<div class="trix-content">
{% autoescape off %} {{ article.content }} {% endautoescape %}
</div>
</body>

编辑页面

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<link rel="stylesheet" type="text/css" href="/static/css/trix.css" />
<script type="text/javascript" src="/static/js/trix.js"></script>

<form action="{% url 'edit_homepage' %}" method="POST">
{% csrf_token %}
<input
id="id_content"
type="hidden"
name="content"
value="{{ article.content }}"
/>
<trix-editor input="id_content" class="trix-content"></trix-editor>
<input type="submit" value="save" />
</form>

要实现拖拽或 ctrl V 添加图片,需要 AJAX 脚本。attachment.js
将图片传递给后端,传递成功后根据 url 生成规则设置当前图片的 url

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
(function () {
var HOST = "/wiki/upload_ajax";

addEventListener("trix-attachment-add", function (event) {
if (event.attachment.file) {
uploadAttachment(event.attachment);
}
});

function uploadAttachment(attachment) {
var file = attachment.file;
var name = createStorageKey(file);
var form = new FormData();
form.append("img", file);
form.append("name", name);
var xhr = new XMLHttpRequest();
xhr.open("POST", HOST, true);

xhr.upload.addEventListener("progress", function (event) {
var progress = (event.loaded / event.total) * 100;
attachment.setUploadProgress(progress);
});

xhr.addEventListener("load", function (event) {
if (xhr.status == 200) {
attachment.setAttributes({ url: ["/media/img", name].join("/") });
}
});

xhr.send(form);
}

function createStorageKey(file) {
var date = new Date();
var day = date.toISOString().slice(0, 10);
var name = date.getTime() + "-" + file.name;
// return [ "/media","img", day, name ].join("/")
return name;
}

function createFormData(key, file) {
var data = new FormData();
data.append("key", key);
data.append("file", file);
data.append("Content-Type", file.type);
return data;
}
})();

处理 ajax 请求的的函数,将 js 传递的文件,保存在数据库,

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@csrf_exempt
def upload_ajax(request):
temp_name = "wiki/wiki-header.html"
if request.method == 'POST':
#print (request.FILES.get('img').name)
img_name = request.POST.get('name')
#print (request.POST.get('name'))
new_img = IMG(
img = request.FILES.get('img'),
name = request.POST.get('name')
)
new_img.img.name = request.POST.get('name')
new_img.save()
#img_url = IMG.objects.get(name=img_name).img.url
#print img_url
#return img_url

return render(request,'wiki/edit_homepage.html',locals())

效果


参考

https://www.cnblogs.com/14061216chen/p/6537864.html django 传图片
http://www.cnblogs.com/ccorz/p/5912478.html ajax 原理