Django + ueditor + upload = 完美

写在最上面的废话:
知道很多人都不太有耐心看完一长篇文章,所以这里说明一下,到0x03章节后,所有代码块都只要复制即可。遇到错误或不会地方再回头仔细看文字性说明。

ueditor是非常好的富文本编辑器,但是官方提供的代码只有php、jsp、asp和源码,即,对于这几类语言的支持是比较完整的,包括上传功能。但是对于Django就不是那么友好了,除了提供常规的编辑之外,如果想要上传功能,那么就要费一翻周折了。

ueditor官方的第三方插件中提供了针对Django的上传插件(DjangoUeditor),但是,经过研究发现,该插件是基于Django1.x和python2(大家都知道python2已经被宣布死刑了),在Django2.2和python3.7中存在很多问题,并且因为是安装在site-packages中的,所以配置起来有点麻烦(如,项目静态文件配置等),也不能作为项目部署,在开发环境中配置好后,要在线上环境中重新配置一次。所以,基于这个插件这么多问题,经过了一下午的折腾,借用该插件中件的核心文件,将其创建为一个Django app,并且修复了版本错误,现在分享给大家,希望能帮到大家。

官方:https://ueditor.baidu.com/website/download.html

0x00 安装

pip install ueditor==1.4

0x01 项目结构

safeScan
--safeScan
----urls.py
----settings.py
--ueditorUpload
----views.py
----usettings.py
----utils.py
----urls.py
----apps.py
--static
----ueditor
------各种文件静态文件
----upload     #最后将上传文件,保存到此

0x02 创建一个上传app

创建上传app

python manage.py startapp ueditorUpload

下面两个url中的配置一定要这么写,尤其是路径和views,否则不能与ueditor中的上传代码关联。

# ueditorUpload/urls.py
from django.urls import path
from ueditorUpload import views

app_name="ueditor"
urlpatterns = [
    path("upload", views.get_ueditor_controller, name="ueditor_upload"),
]
# 项目/urls.py
from django.urls import path,include

urlpatterns = [
......
    path('ueditor/',include('ueditorUpload.urls',namespace="ueditor")),   # 如果你也配置了namespace,那么就需要在ueditorUpload apps.py中配置name
]

0x03 核心代码

这里的核心代码就是ueditor官方提供的第三方插件的改版,大家在使用的时候,只需要完全复制即可。如果需要修改静态路径的话,可以自行修改静态路径常量即可。不过这里需要说明的是,虽然经过修改后可以完美支持上传了,但不免还存在错误的地方没有修改到,所以当你copy的时候,还会报各种错误,请留言,或者将自己的修改点留下,帮助更多人,谢谢。

views.py

#coding:utf-8
from importlib import import_module
from django.http import HttpResponse
from . import usettings as USettings
import os
import json
from django.views.decorators.csrf import csrf_exempt
import datetime,random
import urllib


def get_path_format_vars():
    return {
        "year":datetime.datetime.now().strftime("%Y"),
        "month":datetime.datetime.now().strftime("%m"),
        "day":datetime.datetime.now().strftime("%d"),
        "date": datetime.datetime.now().strftime("%Y%m%d"),
        "time":datetime.datetime.now().strftime("%H%M%S"),
        "datetime":datetime.datetime.now().strftime("%Y%m%d%H%M%S"),
        "rnd":random.randrange(100,999)
    }

#保存上传的文件
def save_upload_file(PostFile,FilePath):
    try:
        f = open(FilePath, 'wb')
        for chunk in PostFile.chunks():
            f.write(chunk)
    except Exception as E:
        f.close()
        return u"写入文件错误:"+ E.message
    f.close()
    return u"SUCCESS"


@csrf_exempt
def get_ueditor_settings(request):
    return HttpResponse(json.dumps(USettings.UEditorUploadSettings,ensure_ascii=False), content_type="application/javascript")


@csrf_exempt
def get_ueditor_controller(request):
    """获取ueditor的后端URL地址    """

    action=request.GET.get("action","")
    reponseAction={
        "config":get_ueditor_settings,
        "uploadimage":UploadFile,
        "uploadscrawl":UploadFile,
        "uploadvideo":UploadFile,
        "uploadfile":UploadFile,
        "catchimage":catcher_remote_image,
        "listimage":list_files,
        "listfile":list_files
    }
    return reponseAction[action](request)


@csrf_exempt
def list_files(request):
    """列出文件"""
    if request.method!="GET":
        return  HttpResponse(json.dumps(u"{'state:'ERROR'}") ,content_type="application/javascript")
    #取得动作
    action=request.GET.get("action","listimage")

    allowFiles={
        "listfile":USettings.UEditorUploadSettings.get("fileManagerAllowFiles",[]),
        "listimage":USettings.UEditorUploadSettings.get("imageManagerAllowFiles",[])
    }
    listSize={
        "listfile":USettings.UEditorUploadSettings.get("fileManagerListSize",""),
        "listimage":USettings.UEditorUploadSettings.get("imageManagerListSize","")
    }
    listpath={
        "listfile":USettings.UEditorUploadSettings.get("fileManagerListPath",""),
        "listimage":USettings.UEditorUploadSettings.get("imageManagerListPath","")
    }
    #取得参数
    list_size=int(request.GET.get("size",listSize[action]))
    list_start=int(request.GET.get("start",0))

    files=[]
    root_path=os.path.join(USettings.MEDIA_ROOT,listpath[action]).replace("\\","/")
    files=get_files(root_path,root_path,allowFiles[action])

    if (len(files)==0):
        return_info={
            "state":u"未找到匹配文件!",
            "list":[],
            "start":list_start,
            "total":0
        }
    else:
        return_info={
            "state":"SUCCESS",
            "list":files[list_start:list_start+list_size],
            "start":list_start,
            "total":len(files)
        }

    return HttpResponse(json.dumps(return_info),content_type="application/javascript")


def get_files(root_path,cur_path, allow_types=[]):
    files = []
    items = os.listdir(cur_path)
    for item in items:
        # item=unicode(item)
        item_fullname = os.path.join(root_path,cur_path, item).replace("\\", "/")
        if os.path.isdir(item_fullname):
            files.extend(get_files(root_path,item_fullname, allow_types))
        else:
            ext = os.path.splitext(item_fullname)[1]
            is_allow_list= (len(allow_types)==0) or (ext in allow_types)
            if is_allow_list:
                files.append({
                    "url":urllib.parse.urljoin(USettings.MEDIA_URL ,os.path.join(os.path.relpath(cur_path,root_path),item).replace("\\","/" )),
                    "mtime":os.path.getmtime(item_fullname)
                })

    return files


@csrf_exempt
def UploadFile(request):
    """上传文件"""
    if not request.method=="POST":
        return  HttpResponse(json.dumps(u"{'state:'ERROR'}"),content_type="application/javascript")

    state="SUCCESS"
    action=request.GET.get("action")
    #上传文件
    upload_field_name={
        "uploadfile":"fileFieldName","uploadimage":"imageFieldName",
        "uploadscrawl":"scrawlFieldName","catchimage":"catcherFieldName",
        "uploadvideo":"videoFieldName",
    }
    UploadFieldName=request.GET.get(upload_field_name[action],USettings.UEditorUploadSettings.get(action,"upfile"))

    #上传涂鸦,涂鸦是采用base64编码上传的,需要单独处理
    if action=="uploadscrawl":
        upload_file_name="scrawl.png"
        upload_file_size=0
    else:
        #取得上传的文件
        file=request.FILES.get(UploadFieldName,None)
        if file is None:return  HttpResponse(json.dumps(u"{'state:'ERROR'}") ,content_type="application/javascript")
        upload_file_name=file.name
        upload_file_size=file.size

    #取得上传的文件的原始名称
    upload_original_name,upload_original_ext=os.path.splitext(upload_file_name)

    #文件类型检验
    upload_allow_type={
        "uploadfile":"fileAllowFiles",
        "uploadimage":"imageAllowFiles",
        "uploadvideo":"videoAllowFiles"
    }
    if action in upload_allow_type:
    # if upload_allow_type.has_key(action):
        allow_type= list(request.GET.get(upload_allow_type[action],USettings.UEditorUploadSettings.get(upload_allow_type[action],"")))
        if not upload_original_ext.lower()  in allow_type:
            state=u"服务器不允许上传%s类型的文件。" % upload_original_ext

    #大小检验
    upload_max_size={
        "uploadfile":"filwMaxSize",
        "uploadimage":"imageMaxSize",
        "uploadscrawl":"scrawlMaxSize",
        "uploadvideo":"videoMaxSize"
    }
    max_size=int(request.GET.get(upload_max_size[action],USettings.UEditorUploadSettings.get(upload_max_size[action],0)))
    if max_size!=0:
        from .utils import FileSize
        MF = FileSize(max_size)
        if upload_file_size>MF.size:
            state=u"上传文件大小不允许超过%s。" % MF.FriendValue

    #检测保存路径是否存在,如果不存在则需要创建
    upload_path_format={
        "uploadfile":"filePathFormat",
        "uploadimage":"imagePathFormat",
        "uploadscrawl":"scrawlPathFormat",
        "uploadvideo":"videoPathFormat"
    }

    path_format_var=get_path_format_vars()
    path_format_var.update({
        "basename":upload_original_name,
        "extname":upload_original_ext[1:],
        "filename":upload_file_name,
    })
    #取得输出文件的路径
    OutputPathFormat,OutputPath,OutputFile=get_output_path(request,upload_path_format[action],path_format_var)

    #所有检测完成后写入文件
    if state=="SUCCESS":
        if action=="uploadscrawl":
            state=save_scrawl_file(request, os.path.join(OutputPath,OutputFile))
        else:
            #保存到文件中,如果保存错误,需要返回ERROR
            upload_module_name = USettings.UEditorUploadSettings.get("upload_module", None)
            if upload_module_name:
                mod = import_module(upload_module_name)
                state = mod.upload(file, OutputPathFormat)
            else:
                state = save_upload_file(file, os.path.join(OutputPath, OutputFile))

    #返回数据
    return_info = {

        'url': urllib.parse.urljoin(USettings.MEDIA_URL , OutputPathFormat) ,                # 保存后的文件名称
        'original': upload_file_name,                  #原始文件名
        'type': upload_original_ext,
        'state': state,                         #上传状态,成功时返回SUCCESS,其他任何值将原样返回至图片上传框中
        'size': upload_file_size
    }
    return HttpResponse(json.dumps(return_info,ensure_ascii=False),content_type="application/javascript")

@csrf_exempt
def catcher_remote_image(request):
    """远程抓图,当catchRemoteImageEnable:true时,
        如果前端插入图片地址与当前web不在同一个域,则由本函数从远程下载图片到本地
    """
    if not request.method=="POST":
        return  HttpResponse(json.dumps( u"{'state:'ERROR'}"),content_type="application/javascript")

    state="SUCCESS"

    allow_type= list(request.GET.get("catcherAllowFiles",USettings.UEditorUploadSettings.get("catcherAllowFiles","")))
    max_size=int(request.GET.get("catcherMaxSize",USettings.UEditorUploadSettings.get("catcherMaxSize",0)))

    remote_urls=request.POST.getlist("source[]",[])
    catcher_infos=[]
    path_format_var=get_path_format_vars()

    for remote_url in remote_urls:
        #取得上传的文件的原始名称
        remote_file_name=os.path.basename(remote_url)
        remote_original_name,remote_original_ext=os.path.splitext(remote_file_name)
        #文件类型检验
        if remote_original_ext  in allow_type:
            path_format_var.update({
                "basename":remote_original_name,
                "extname":remote_original_ext[1:],
                "filename":remote_original_name
            })
            #计算保存的文件名
            o_path_format,o_path,o_file=get_output_path(request,"catcherPathFormat",path_format_var)
            o_filename=os.path.join(o_path,o_file).replace("\\","/")
            #读取远程图片文件
            try:
                remote_image=urllib.request.urlopen(remote_url)
                 #将抓取到的文件写入文件
                try:
                    f = open(o_filename, 'wb')
                    f.write(remote_image.read())
                    f.close()
                    state="SUCCESS"
                except Exception as E:
                    state=u"写入抓取图片文件错误:%s" % E.message
            except Exception as E:
                state=u"抓取图片错误:%s" % E.message

            catcher_infos.append({
                "state":state,
                "url":urllib.parse.urljoin(USettings.MEDIA_URL , o_path_format),
                "size":os.path.getsize(o_filename),
                "title":os.path.basename(o_file),
                "original":remote_file_name,
                "source":remote_url
            })

    return_info={
        "state":"SUCCESS" if len(catcher_infos) >0 else "ERROR",
        "list":catcher_infos
    }

    return HttpResponse(json.dumps(return_info,ensure_ascii=False),content_type="application/javascript")


def get_output_path(request,path_format,path_format_var):
    #取得输出文件的路径
    OutputPathFormat=(request.GET.get(path_format,USettings.UEditorSettings["defaultPathFormat"]) % path_format_var).replace("\\","/")
    #分解OutputPathFormat
    OutputPath,OutputFile=os.path.split(OutputPathFormat)       #80-80_20190910173915_792.jpg
    OutputPath=os.path.join(USettings.MEDIA_ROOT,OutputPath)
    if not OutputFile:#如果OutputFile为空说明传入的OutputPathFormat没有包含文件名,因此需要用默认的文件名
        OutputFile=USettings.UEditorSettings["defaultPathFormat"] % path_format_var
        OutputPathFormat=os.path.join(OutputPathFormat,OutputFile)
    if not os.path.exists(OutputPath):
        os.makedirs(OutputPath)
    return ( OutputPathFormat,OutputPath,OutputFile)

#涂鸦功能上传处理
@csrf_exempt
def save_scrawl_file(request,filename):
    import base64
    try:
        content=request.POST.get(USettings.UEditorUploadSettings.get("scrawlFieldName","upfile"))
        f = open(filename, 'wb')
        #f.write(base64.decodestring(content)) 修改为下一句,可以添加涂鸦图片
        f.write(base64.decodebytes(content.encode("utf-8")))
        f.close()
        state="SUCCESS"
    except Exception as E:
        state="写入图片文件错误:%s" % E.message
    return state

utils.py

#coding: utf-8
#文件大小类
class FileSize(object):
    SIZE_UNIT={"Byte":1,"KB":1024,"MB":1048576,"GB":1073741824,"TB":1099511627776}
    def __init__(self,size):
        self._size=size		# 官方插件self.size和size方法名称重复,会导致setter重复执行,导致RuntimeError: maximum recursion depth exceeded

    @staticmethod
    def Format(size):
        import re
        if isinstance(size,int):
            return size
        else:
            if not isinstance(size,str):
                return 0
            else:
                oSize=size.lstrip().upper().replace(" ","")
                pattern=re.compile(r"(\d*\.?(?=\d)\d*)(byte|kb|mb|gb|tb)",re.I)
                match=pattern.match(oSize)
                if match:
                    m_size, m_unit=match.groups()
                    if m_size.find(".")==-1:
                        m_size=int(m_size)
                    else:
                        m_size=float(m_size)
                    if m_unit!="BYTE":
                        return m_size*FileSize.SIZE_UNIT[m_unit]
                    else:
                        return m_size
                else:
                    return 0

    #返回字节为单位的值
    @property
    def size(self):
        return self._size

    @size.setter
    def size(self,newsize):
        try:
            self._size=newsize
        except:
            self._size=0



    #返回带单位的自动值
    @property
    def FriendValue(self):
        if self._size<FileSize.SIZE_UNIT["KB"]:
            unit="Byte"
        elif self._size<FileSize.SIZE_UNIT["MB"]:
            unit="KB"
        elif self._size<FileSize.SIZE_UNIT["GB"]:
            unit="MB"
        elif self._size<FileSize.SIZE_UNIT["TB"]:
            unit="GB"
        else:
            unit="TB"

        if (self._size % FileSize.SIZE_UNIT[unit])==0:
            return "%s%s" % ((self._size / FileSize.SIZE_UNIT[unit]),unit)
        else:
            return "%0.2f%s" % (round(float(self._size) /float(FileSize.SIZE_UNIT[unit]) ,2),unit)

    def __str__(self):
        return self.FriendValue

    #相加
    def __add__(self, other):
        if isinstance(other,FileSize):
            return FileSize(other.size+self._size)
        else:
            return FileSize(FileSize(other).size+self._size)
    def __sub__(self, other):
        if isinstance(other,FileSize):
            return FileSize(self._size-other.size)
        else:
            return FileSize(self._size-FileSize(other).size)
    def __gt__(self, other):
        if isinstance(other,FileSize):
            if self._size>other.size:		
                return True
            else:
                return False
        else:
            if self._size>FileSize(other).size:
                return True
            else:
                return False
    def __lt__(self, other):
        if isinstance(other,FileSize):
            if other.size>self._size:
                return True
            else:
                return False
        else:
            if FileSize(other).size > self._size:
                return True
            else:
                return False
    def __ge__(self, other):
        if isinstance(other,FileSize):
            if self._size>=other.size:
                return True
            else:
                return False
        else:
            if self._size>=FileSize(other).size:
                return True
            else:
                return False
    def __le__(self, other):
        if isinstance(other,FileSize):
            if other.size>=self._size:
                return True
            else:
                return False
        else:
            if FileSize(other).size >= self._size:
                return True
            else:
                return False

usettings.py

usettings.py这个名称,是为了与全局里的其它配置文件名称区分开,在其它地方引用时,也要修改。这个文件里有两个设置静态路径的常量,MEDIA_ROOT = STATIC_ROOT + os.sep + "upload"MEDIA_URL = STATIC_URL + "upload/",这个常量可以在项目全局配置文件settings.py中设置,然后引用,这样可以保证全局一致,你也可以写死在这里。全局配置文件settings.py中这两个参数为:# STATIC_ROOT = os.path.join(BASE_DIR,"static") # linux 用这个,不能用/static/,这样会导入到根目录STATIC_ROOT = os.path.join(BASE_DIR,"d:\\workspace\\safeScan\\static") # windows 用这个,用上面那个会报错:(staticfiles.E002) The STATICFILES_DIRS setting should not contain the STATISTATIC_URL = '/static/'

#coding:utf-8
from django.conf import settings as gSettings   #全局设置
from safeScan.settings import STATIC_URL,STATIC_ROOT
import os

MEDIA_ROOT = STATIC_ROOT + os.sep + "upload"
MEDIA_URL = STATIC_URL + "upload/"
#工具栏样式,可以添加任意多的模式
TOOLBARS_SETTINGS={
    "besttome":[['source','undo', 'redo','bold', 'italic', 'underline','forecolor', 'backcolor','superscript','subscript',"justifyleft","justifycenter","justifyright","insertorderedlist","insertunorderedlist","blockquote",'formatmatch',"removeformat",'autotypeset','inserttable',"pasteplain","wordimage","searchreplace","map","preview","fullscreen"], ['insertcode','paragraph',"fontfamily","fontsize",'link', 'unlink','insertimage','insertvideo','attachment','emotion',"date","time"]],
    "mini":[['source','|','undo', 'redo', '|','bold', 'italic', 'underline','formatmatch','autotypeset', '|', 'forecolor', 'backcolor','|', 'link', 'unlink','|','simpleupload','attachment']],
    "normal":[['source','|','undo', 'redo', '|','bold', 'italic', 'underline','removeformat', 'formatmatch','autotypeset', '|', 'forecolor', 'backcolor','|', 'link', 'unlink','|','simpleupload', 'emotion','attachment', '|','inserttable', 'deletetable', 'insertparagraphbeforetable', 'insertrow', 'deleterow', 'insertcol', 'deletecol', 'mergecells', 'mergeright', 'mergedown', 'splittocells', 'splittorows', 'splittocols']]
}

#默认的Ueditor设置,请参见ueditor.config.js
UEditorSettings={
    "toolbars":TOOLBARS_SETTINGS["normal"],
    "autoFloatEnabled":False,
    "defaultPathFormat":"%(basename)s_%(datetime)s_%(rnd)s.%(extname)s"   #默认保存上传文件的命名方式
}
#请参阅php文件夹里面的config.json进行配置
UEditorUploadSettings={
   #上传图片配置项
    "imageActionName": "uploadimage", #执行上传图片的action名称
    "imageMaxSize": 10485760, #上传大小限制,单位B,10M
    "imageFieldName": "upfile", #* 提交的图片表单名称 */
    "imageUrlPrefix":"",
    "imagePathFormat":"",
    "imageAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #上传图片格式显示

    #涂鸦图片上传配置项 */
    "scrawlActionName": "uploadscrawl", #执行上传涂鸦的action名称 */
    "scrawlFieldName": "upfile", #提交的图片表单名称 */
    "scrawlMaxSize": 10485760, #上传大小限制,单位B  10M
    "scrawlUrlPrefix":"",
    "scrawlPathFormat":"",

    #截图工具上传 */
    "snapscreenActionName": "uploadimage", #执行上传截图的action名称 */
    "snapscreenPathFormat":"",
    "snapscreenUrlPrefix":"",

    #抓取远程图片配置 */
    "catcherLocalDomain": ["127.0.0.1", "localhost", "img.baidu.com"],
    "catcherPathFormat":"",
    "catcherActionName": "catchimage", #执行抓取远程图片的action名称 */
    "catcherFieldName": "source", #提交的图片列表表单名称 */
    "catcherMaxSize": 10485760, #上传大小限制,单位B */
    "catcherAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #抓取图片格式显示 */
    "catcherUrlPrefix":"",
    #上传视频配置 */
    "videoActionName": "uploadvideo", #执行上传视频的action名称 */
    "videoPathFormat":"",
    "videoFieldName": "upfile", # 提交的视频表单名称 */
    "videoMaxSize": 102400000, #上传大小限制,单位B,默认100MB */
    "videoUrlPrefix":"",
    "videoAllowFiles": [
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid"], #上传视频格式显示 */

    #上传文件配置 */
    "fileActionName": "uploadfile", #controller里,执行上传视频的action名称 */
    "filePathFormat":"",
    "fileFieldName": "upfile",#提交的文件表单名称 */
    "fileMaxSize": 204800000, #上传大小限制,单位B,200MB */
    "fileUrlPrefix": "",#文件访问路径前缀 */
    "fileAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml"
    ], #上传文件格式显示 */

    #列出指定目录下的图片 */
    "imageManagerActionName": "listimage", #执行图片管理的action名称 */
    "imageManagerListPath":"",
    "imageManagerListSize": 30, #每次列出文件数量 */
    "imageManagerAllowFiles": [".png", ".jpg", ".jpeg", ".gif", ".bmp"], #列出的文件类型 */
    "imageManagerUrlPrefix": "",#图片访问路径前缀 */

    #列出指定目录下的文件 */
    "fileManagerActionName": "listfile", #执行文件管理的action名称 */
    "fileManagerListPath":"",
    "fileManagerUrlPrefix": "",
    "fileManagerListSize": 30, #每次列出文件数量 */
    "fileManagerAllowFiles": [
        ".png", ".jpg", ".jpeg", ".gif", ".bmp",".tif",".psd"
        ".flv", ".swf", ".mkv", ".avi", ".rm", ".rmvb", ".mpeg", ".mpg",
        ".ogg", ".ogv", ".mov", ".wmv", ".mp4", ".webm", ".mp3", ".wav", ".mid",
        ".rar", ".zip", ".tar", ".gz", ".7z", ".bz2", ".cab", ".iso",
        ".doc", ".docx", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".md", ".xml",
        ".exe",".com",".dll",".msi"
    ] #列出的文件类型 */
}


#更新配置:从用户配置文件settings.py重新读入配置UEDITOR_SETTINGS,覆盖默认
def UpdateUserSettings():
    UserSettings=getattr(gSettings,"UEDITOR_SETTINGS",{}).copy()
    # if UserSettings.has_key("config"):UEditorSettings.update(UserSettings["config"])
    if "config" in UEditorSettings:UEditorSettings.update(UserSettings["config"])
    # if UserSettings.has_key("upload"):UEditorUploadSettings.update(UserSettings["upload"])
    if "upload" in UserSettings:UEditorUploadSettings.update(UserSettings["upload"])

#读取用户Settings文件并覆盖默认配置
UpdateUserSettings()


#取得配置项参数
def GetUeditorSettings(key,default=None):
    if UEditorSettings.has_key(key):
        return UEditorSettings[key]
    else:
        return default

0x04 效果

Django + ueditor + upload = 完美_第1张图片
Django + ueditor + upload = 完美_第2张图片
Django + ueditor + upload = 完美_第3张图片

注意

注意1

在我的线上环境中,有一个小小的bug,当使用单一图片上传时,需要在上传完图片后面加【空格】或【回车】等其它字符,否则保存文章时,图片失败,具体原因。【就是少了

<body class="view" contenteditable="true" spellcheck="false" style="overflow-y: hidden; height: 297px; cursor: text;">
<p>
<img src="/static/upload/658-170_20190911164838_254.png" title="" _src="/static/upload/658-170_20190911164838_254.png" alt="658-170.png">&#8203;
</p>
</body>

注意2

虽然这个配置视频和音乐都可以上传,但该插件使用的都是flash方式,在当前浏览器下,基本不要想flash了。

你可能感兴趣的:(django,ueditor,django,上传)