Django整合Ueditor最新版

之前记录了两篇关于整合Ueditor的文章:Flask之封装ueditorvue使用ueditor前端配置django使用ueditor服务器端配置。其中在django使用ueditor服务器端配置我们采用的第三方包解决这个问题,然已经停更了,暂时急用也没有去费心封装一个类似的应用,网上有另一个包也可以帮我们解决这个问题,那就是DUEditor

该文档写的也很详细,但是使用起来有些许坑需要我们来填下。另外文档中有一些笔误,我这边直接将该文档说明拿过来,就直接修改其中的笔误了。

安装方法

因为配置个性化问题,本项目暂不支持pip install,如想使用,下载以后,把DUEditor扔到django项目目录即可,记得使用该仓库的DUEditor应用即可,没必要把整个项目down下来

INSTALL_APPS

INSTALL_APPS里面增加DUEditor app,如下:

1
2
3
4
INSTALLED_APPS = (
#........
'DUEditor',
)

路由添加

urls.py中增加:

1
path('ueditor/',include('DUEditor.urls' )),

模型定义

models中这样定义:

1
2
3
4
5
6
7
8
9
10
11
12
from DUEditor.models import UEditorField
class Blog(models.Model):
Name=models.CharField(,max_length=100,blank=True)
Content=UEditorField('内容 ',height=100,width=500,default='test',toolbars='mini',options={"elementPathEnabled":True},blank=True)

# 说明:
# UEditorField继承自models.TextField,因此你可以直接将model里面定义的models.TextField直接改成UEditorField即可。
# UEditorField提供了额外的参数:
# toolbars:配置你想显示的工具栏,取值为mini,normal,full,besttome, 代表小,一般,全部,涂伟忠贡献的一种样式。如果默认的工具栏不符合您的要求,您可以在settings里面配置自己的显示按钮。参见后面介绍。
# options:其他UEditor参数,字典类型。参见Ueditor的文档ueditor_config.js里面的说明。
# css:编辑器textarea的CSS样式
# width,height:编辑器的宽度和高度,以像素为单位。

表单使用

在表单中使用非常简单,与常规的form字段没什么差别,如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
class TestUeditorModelForm(forms.ModelForm):
class Meta:
model=Blog
# 如果不是用ModelForm,可以有两种方法使用:

# 1: 使用forms.UEditorField

from DUEditor.forms import UEditorField
class TestUEditorForm(forms.Form):
Description=UEditorField("描述",initial="abc",width=600,height=800)

# 2: widgets.UEditorWidget

from UEditor.widgets import UEditorWidget
class TestUEditorForm(forms.Form):
Content=forms.CharField(label="内容",widget=UEditorWidget(width=800,height=500,toolbars={}))

# widgets.UEditorWidget和forms.UEditorField的输入参数与上述models.UEditorField一样。

Settings配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
在Django的Settings可以配置以下参数:
UEDITOR_SETTINGS={
"toolbars":{ #定义多个工具栏显示的按钮,允行定义多个
"name1":[[ 'source', '|','bold', 'italic', 'underline']],
"name2":[]
},
"images_upload":{
"allow_type":"jpg,png", #定义允许的上传的图片类型
"max_size":"2222kb" #定义允许上传的图片大小,0代表不限制
},
"files_upload":{
"allow_type":"zip,rar", #定义允许的上传的文件类型
"max_size":"2222kb" #定义允许上传的文件大小,0代表不限制
},,
"image_manager":{
"location":"" #图片管理器的位置,如果没有指定,默认跟图片路径上传一样
},
}

在模板里面:

1
2
3
4
5
6
<head>
......
{{ form.media }} #这一句会将所需要的CSS和JS加进来。
......
</head>
注:运行collectstatic命令,将所依赖的css,js之类的文件复制到{{STATIC_ROOT}}文件夹里面。

inclusion tag的使用

1
2
3
4
5
{%load ueditor_tags %}
<script id="container" name="container" style="display: inline-block;" type="text/plain">
初始化内容
</script>
{%ueditor "container"%}

其他事项

  • 本程序安装包里面已经包括了Ueditor,不需要再额外安装。
  • 目前暂时不支持ueditor的插件
  • 别忘记了运行collectstatic命令,该命令可以将ueditor的所有文件复制到文件夹里面
  • Django默认开启了CSRF中间件,因此如果你的表单没有加入{% csrf_token %},那么当您上传文件和图片时会失败
  • 不过编辑器里面的图片上传View做了CSRF取消设置
  • 上传图片失败提示:Refused to display ‘127.0.0.1:8000/ueditor/controller/?imagePathFormat=&filePathFormat=&action=uploadimage’ in a frame because it set ‘X-Frame-Options’ to ‘deny’.解决方案:注释掉中间件中的’django.middleware.clickjacking.XFrameOptionsMiddleware‘。

实例

助手函数

1
2
3
4
5
6
7
8
9
10
11
app.helper.generate_filepath.py

import uuid
def generate_filepath(instanse, filename):
'''生成新的文件'''
# 获取文件后缀
ext = filename.split('.')[-1]
# 随机生成文件名
filename = "%s.%s" % (uuid.uuid4().hex, ext)
# 返回新文件名
return filename

模型

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
from django.db import models

from DUEditor.models import UEditorField

from app.helper import generate_filepath
# Create your models here.
# 通用字段
class Common(models.Model):
id = models.AutoField(primary_key = True)
keyword = models.CharField(max_length=255, verbose_name='关键词', null=True, blank=True)
description = models.CharField(max_length=255, verbose_name='描述', null=True, blank=True)
created_time = models.DateTimeField(auto_now_add=True, verbose_name='创建时间')
updated_time = models.DateTimeField(auto_now=True, verbose_name='更新时间')
deleted_time = models.DateTimeField(verbose_name='删除时间', null=True, blank=True)
def __str__(self):
return self.title if hasattr(self, 'title') else self.name
class Meta:
abstract = True
class Post(Common):
title = models.CharField(max_length=50, verbose_name='单页标题', null=True, blank=True)
thumbnail = models.ImageField(upload_to=generate_filepath, null=True, blank=True, verbose_name='缩略图')
body = UEditorField(verbose_name='内容', toolbars="full", null=True, blank=True)
cat = models.ForeignKey(to=Cat, verbose_name='栏目', on_delete=models.CASCADE, null=True, blank=True)
class Meta:
verbose_name = '文章'
verbose_name_plural = verbose_name

视图

我这里使用的django admin,实际视图参照文档即可:

路由

1
2
3
4
5
6
7
8
9
10
11
12
from django.contrib import admin
from django.urls import path, re_path, include
from django.conf import settings
from django.views.static import serve

from app import views
urlpatterns = [
path('admin/', admin.site.urls),
path('test/', views.test),
re_path('^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}),
path('ueditor/',include('DUEditor.urls' )),
]

settings

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
"""
Django settings for wechat project.

Generated by 'django-admin startproject' using Django 3.0.5.

For more information on this file, see
https://docs.djangoproject.com/en/3.0/topics/settings/

For the full list of settings and their values, see
https://docs.djangoproject.com/en/3.0/ref/settings/
"""

import os

# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))


# Quick-start development settings - unsuitable for production
# See https://docs.djangoproject.com/en/3.0/howto/deployment/checklist/

# SECURITY WARNING: keep the secret key used in production secret!
SECRET_KEY = 'cx2qq($r2ux^0%b6xm7+gz=_mzt=5a#5&@j@ahp_*72%933)ng'

# SECURITY WARNING: don't run with debug turned on in production!
DEBUG = True

ALLOWED_HOSTS = []


# Application definition

INSTALLED_APPS = [
'django.contrib.admin',
'django.contrib.auth',
'django.contrib.contenttypes',
'django.contrib.sessions',
'django.contrib.messages',
'django.contrib.staticfiles',
'app.apps.AppConfig',
'DUEditor'
]

MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
# DUEditor图片上传失败
# 'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
from django.middleware.clickjacking import XFrameOptionsMiddleware
ROOT_URLCONF = 'wechat.urls'


WSGI_APPLICATION = 'wechat.wsgi.application'




# Internationalization
# https://docs.djangoproject.com/en/3.0/topics/i18n/

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False


# Static files (CSS, JavaScript, Images)
# https://docs.djangoproject.com/en/3.0/howto/static-files/
# 配置上传路径
MEDIA_ROOT = os.path.join(BASE_DIR, 'uploads')
# 配置访问上传文件的公用url路径
MEDIA_URL = '/media/'

STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static/"),
]
STATIC_URL = '/static/'
STATIC_ROOT = os.path.join(BASE_DIR, "static_new/")


UEDITOR_SETTINGS={
"toolbars":{ #定义多个工具栏显示的按钮,允行定义多个
"name1":[[ 'source', '|','bold', 'italic', 'underline']],
"name2":[]
},
"images_upload":{
"allow_type":"jpg,png",#定义允许的上传的图片类型
"max_size":"2222kb" #定义允许上传的图片大小,0代表不限制
},
"files_upload":{
"allow_type":"zip,rar", #定义允许的上传的文件类型
"max_size":"2222kb" #定义允许上传的文件大小,0代表不限制
},
"image_manager":{
"location":"" #图片管理器的位置,如果没有指定,默认跟图片路径上传一样
},
}

以上只放了跟DUEditor相关的配置,数据库等其他配置按照自己实际设置

收集静态文件

1
python manage.py collectstatic

最终结果

img