实现方法是学习django快速集成富文本编辑器wangeditor_轻编程的博客-CSDN博客 的方法,感谢博主。代码有不完善、不强大的地方,在生成环境需要继续完善,主要是学习思路。
一、环境:
python: 3.8
Django :3.2.16
wangeditor: v4 (官方文档地址:wangEditor)
JS文件下载:https://download.csdn.net/download/weixin_47401101/87379142
编译器:pycharm
二、Django项目后台admin使用wangeditor的方法步骤
1、在项目的settings.py中需要进行的设置,在TEMPLATES中加入关于media的引入,用来处理图片上传的需要。
TEMPLATES = [
{
'OPTIONS': {
'context_processors': [
'django.template.context_processors.media', #专门用来处理图片上传
],
},
},
]
# 配置用户上传路径
MEDIA_URL = '/media/' #图片保存路径位于项目的根目录下吗的media问价夹中
MEDIA_ROOT = BASE_DIR / 'media/'
2、在models.py中设计模型,准备插入富文本编辑器wangeditor的字段使用TexitFidle类型
class article(models.Model):
xuhao = models.SmallIntegerField(verbose_name='序号',null=True)
title = models.CharField(verbose_name='标题',max_length=64,null=True)
content = models.TextField(verbose_name='内容')#在后台将富文本编辑器插入到这个字段中
3、admin.py,原理是django的ModelAdmin为提供了一个Media的源类来把js文件插入到页面中去,使用此方法来实现js文件的插入。wangeditor.min.js文件也可以下载到自己的项目中,通过路径引用,例如:'js/wangEditor.min.js'
from django.contrib import admin
from app01.models import content #引入models中设计的模型
@admin.register(article)
class articleAdmin(admin.ModelAdmin):
list_display = ('xuhao','title','content') #设置后台显示的字段
class Media: #通过此方法将js文件插入到页面中
js = (
'admin/js/vendor/jquery/jquery.min.js', #Django自带的jQuery
#通过CDN的方法引入wangeditor的js文件
'https://cdn.jsdelivr.net/npm/wangeditor@latest/dist/wangEditor.min.js',
'js/wang_editor_config.js' #wangeditor主要的配置文件
)
4、页面分析
标号1中的Articles是之前设计的article模型,点击标号2中的ADD,弹出右侧的页面,标号3就是model中的‘content’字段。标号4是3对应的源代码位置,富文本编辑器将会插入到这个div中,div的class为:class="form-row field-content"。
5、wang_editor_config.js,下面的代码可以直接使用,注意看注释,注释比较乱,复用的时候需要修改的地方都标注出来了。
$(document).ready(function () {
// 创建富文本编辑器元素节点
var wehtml = ""
// 获取div,复用的时候.field-content是根据实际情况进行修改
var field_div = document.querySelectorAll(".field-content>div")
//给富文本编辑器的DIV加入label,因为下面把原有div的label隐藏了
field_div[0].insertAdjacentHTML('afterbegin', '内容:');
//插入上面定义的wehtml
field_div[0].insertAdjacentHTML('beforeend', wehtml);
//隐藏原有div的label值,避免重复出现两个框,复用的时候修改下面的.field-content
$(".field-content>div>label").attr('style', 'display:none')
const E = window.wangEditor
const editor = new E("#wangcontent")
//复用的时候下面的ID需要根据情况修改
const $text1 = $('#id_content')
console.log($text1.val())
editor.config.onchange = function (html) {
// 第二步,监控变化,同步更新到 textarea
$text1.val(html)
}
editor.config.height = 500
// 配置 server 接口地址,复用的时候
editor.config.uploadImgServer = '/uploadimage/'
editor.config.uploadFileName = 'spuImg'
editor.create()
editor.txt.html($text1.val())
// 第一步,初始化 textarea 的值
$text1.val(editor.txt.html())
//隐藏原有的输入框
$text1.attr("style","display:none")
})
6、views.py
from django.http import JsonResponse
from django.conf import settings
# 引入登录验证,只有登录了才能上传图片
from django.contrib.auth.mixins import LoginRequiredMixin
# 引入Django的基类视图
from django.views.generic import View
# 引入屏蔽CSRF的方法
from django.views.decorators.csrf import csrf_exempt
#类视图装饰器使用的时候,必须包裹在这个里面
from django.utils.decorators import method_decorator
class UploadImage(LoginRequiredMixin, View):
"""富文本编辑器上传图片
首先会检查项目根目录有没有media/upload/的文件夹
如果没有就创建,图片最终保存在media/upload/目录下
返回图片路径为 "/media/upload/file.png"
如果因为权限不够,不能创建media,就手动进行创建。
"""
@method_decorator(csrf_exempt)
def dispatch(self, *args, **kwargs):
return super().dispatch(*args, **kwargs)
def post(self, request, *args, **kwargs):
import os
import uuid
file_data = request.FILES
keys = list(file_data.keys())
# 使用项目根目录拼接路径
file_path = settings.BASE_DIR / 'media/upload/'
if os.path.exists(file_path) is False:
os.mkdir(file_path)
# 返回数据中需要的data
data = []
for key in keys:
img_dict = {}
file = file_data.get(f'{key}')
# 重命名文件名称
names = list(os.path.splitext(file.name))
names[0] = ''.join(str(uuid.uuid4()).split('-'))
file.name = ''.join(names)
new_path = os.path.join(file_path, file.name)
# 开始上传
with open(new_path, 'wb+') as f:
for chunk in file.chunks():
f.write(chunk)
# 构造返回数据
img_dict['url'] = f'/media/upload/{file.name}'
data.append(img_dict)
context = {"errno": 0, "data": data}
return JsonResponse(context)
7、urls.py
from django.conf import settings
from django.conf.urls.static import static
urlpatterns = [
path('admin/', admin.site.urls),
#下面是上传图片的url
path("uploadimage/", views.UploadImage.as_view(), name="upload_img"),
]
# 使用nigx部署的时候就不需要这么设置了,转发静态文件就可以了,只是调试的需要这么操作
urlpatterns += static(settings.STATIC_URL,document_root = settings.STATIC_ROOT)
urlpatterns += static(settings.MEDIA_URL,document_root = settings.MEDIA_ROOT)
8、效果展示,可以上传图片,可以上传多张图片。
三、Django项目前端使用wangeditor的方法
上面实现了在admin管理页面插入wangeditor的方法,那么如果在前端需要插入wangeditor怎么使用呢,方法类似,下面举例说明,例子延续上面的案例继续进行。
1、views.py,使用上文定义的article模型,通过ModelForm向前端生成一个添加页面。
class articleModelForm(BootStrapModelForm):
class Meta:
model = models.article
fields= "__all__"
def article_add(request):
if request.method == 'GET':
form = articleModelForm()
return render(request,"add.html",{"form":form})
form = articleModelForm(data=request.POST)
if form.is_valid():
# 如果数据合法,保存到数据库
form.save()
return redirect('/list/')
# 校验失败(在页面上显示错误信息)
return render(request, 'add.html', {"form": form})
2、add.html
{% extends 'layout.html' %}
{% block content %}
wangeditor测试
{#novalidate的作用是禁止浏览器自动校验#}
{% endblock %}
3、layout.html
head标签中插入的两行代码是关键,是向模板中导入wangeditor的JS文件和Django自带的jQuery文件。也可以在试用的页面插入,不用全局插入。
{% load static %}
业务系统
{#导入bootstrap#}
{#下面两行是关键,是向模板中导入wangeditor的JS文件和Django自带的jQuery文件#}
{#去掉导航的圆角样式#}
{#定义一个可以插入css的模块#}
{% block css %}
{% endblock %}
{# django中的模板继承练习,设置模板,相当于占位符 #}
{% block content %}
{% endblock %}
{#引入JS文件#}
{#定义一个可以插入js的模块#}
{% block js %}
{% endblock %}
4、页面效果,页面中内容部分就是需要插入wangeditor富文本编辑器的地方
5、页面分析
下图中序号1、2显示成功插入两个JS文件;
序号3是准备插入的位置,序号4是对应的源代码。
序号4中,准备插入的位置位于class="form-group"的第三个div标签内,与admin管理页面不同的是,没有格式的问题label标签可以继续使用,就不用在插入label。所以JS代码稍有不同。
6、加入JS代码后的add.html页
{% extends 'layout.html' %}
{% block content %}
wangeditor测试
{#novalidate的作用是禁止浏览器自动校验#}
{% endblock %}
{% block js %}
{% endblock %}
7、效果
8、前端列表展示输入的内容list.html
前端通过modelform生成展示页面list.html,在前端需要做一下设置。要使用{% autoescape off %}和{% endautoescape %}模板标签将要展示的内容包裹起来,就可以了。
{% autoescape off %}
{% extends 'layout.html' %}
{% block content %}
文章列表
序号
标题
内容
{% for obj in queryset %}
{{ obj.xuhao }}
{{ obj.title}}
{% autoescape off %}
{{ obj.content }}
{% endautoescape %}
{% endfor %}
{% endblock %}