django项目admin后台整合tinymce富文本编辑并自定义添加图片本地上传和富文本中的回显
前言
我们常因为django的自带admin后台功能而选择该框架,但也因为其自动生成的特殊性而在做出特别的更改的时候束手束脚,鉴于项目已经采用了django,而后台要求能够直接上传富文本内容直接用于网页显示,定制性高,后来翻了目前较为知名的几款富文本编辑框,觉得还是tinymce符合能够集成到django admin的简便条件,但是tinymce免费版不提供图片本地上传的服务,所以只能自己找办法集成图片上传到tinymce,以下记录一遍说明过程。
创建满足条件的django项目
项目环境:
python2.7.13
django1.11.6
windows 10
该环境下创建了一个最初始的django项目,models.py中添加了一个用于测试的model,其中用于关联富文本显示的为TextField字段,代码如下:
models.py
# -*-coding:utf-8 -*- from django.db import models # Create your models here. class TestTinymce(models.Model): title = models.CharField("标题", max_length=20, default="") content = models.TextField("文本", default="") class Meta: db_table = "test_tinymce" verbose_name = "测试" verbose_name_plural = "测试" def __unicode__(self): return self.title
之后使用命令建表,使得项目能够运行起来,并添加django admin登录用户名密码等,使得项目能够进入到后台界面,并且在admin.py中注册,使得我们添加的表格能够在django admin中使用起来,进入以下界面:
此时的添加测试数据页面,TextField字段显示为普通的文本域:
Tinymce处理
tinymce官方下载为https://www.tinymce.com/downl...
下载其中的Download TinyMCE Community到本地解压,取出其中的tinymce目录,整个复制到django项目中你的静态文件目录,目前的文件目录如下:
整合django admin和tinymce
整合tinymce和django admin重要的是需要在django后台加载的时候初始化tinymce的初始化函数,按照指定的参数生成对应的富文本框,我们通过admin.py来加载js到对应的model处理界面:
admin.py
# -*-coding:utf-8 -*- from django.contrib import admin import models # Register your models here. class TestTinymce_Admin(admin.ModelAdmin): class Media: js = [ '/static/tinymce/js/jquery.min.js', # 必须首先加载的jquery,手动添加文件 '/static/tinymce/js/tinymce/tinymce.min.js', # tinymce自带文件 '/static/tinymce/js/tinymce/plugins/jquery.form.js', # 手动添加文件 '/static/tinymce/js/tinymce/textarea.js', # 手动添加文件,用户初始化参数 ] admin.site.register(models.TestTinymce, TestTinymce_Admin)
其中jquery.min.js为普通的jquery文件,版本合适即可,tinymce.min.js为tinymce自带文件,jquery.form.js为手动添加,是一个form插件,支持ajax表单提交和ajax文件上传,textarea.js是我自定义的一个js,写的初始化对应的富文本的参数,包含指定图片上传的指定处理路径。
textarea.js
tinymce.init({ selector: "textarea", // 选择该页面绑定的标签 themes: "modern", menubar: false, convert_urls: false, height: 450, plugins: [ 'advlist autolink lists link image charmap print preview hr anchor pagebreak', 'searchreplace wordcount visualblocks visualchars code fullscreen', 'insertdatetime media nonbreaking save table contextmenu directionality', 'emoticons template paste textcolor colorpicker textpattern imagetools', "link imageupload" ], toolbar: "undo redo | imageupload link | bold italic | styleselect fontselect fontsizeselect | bullist numlist outdent indent | alignleft aligncenter alignright alignjustify | print preview media | forecolor backcolor emoticons", content_css: [ '//fast.fonts.net/cssapi/e6dc9b99-64fe-4292-ad98-6974f93cd2a2.css', '//www.tinymce.com/css/codepen.min.css' ], imageupload_url: '/upload_img/', // 指定图片上传处理目录 language:'zh_CN' });
注:其中为了显示为中文,标明了中文zh_CN,同时需要下载语言包zh_CN.js放到对应的langs文件夹下。此时,django admin中的文本域已经被富文本框代替,我们此时只需要把对应的图片上传整合:
整合上传图片功能到tinymce
添加图片上传插件imageupload到plugins文件夹下,此时就符合了我们在textarea.js中toolbar参数中添加的imageupload,同时下载jquery.form.js在符合我们在admin.py加载的路径放置:
此时我们可以看见在富文本框上指定位置出现了图片上传的按钮,点击出现上传本地文件的按钮:
在弹出按钮出现之后,我们处理imageupload_url: '/upload_img/'
上传文件的路径背后的视图处理,根据django的映射规则,我们在urls.py添加路径:
url(r'^upload_img/$', views.upload_img), # 后台富文本框上传图片
添加views.py中的处理接收上传的函数upload_img
:
# -*-coding:utf-8 -*- from django.shortcuts import render from django.views.decorators.csrf import csrf_exempt import json import time from PIL import Image from django.conf import settings from django.http import HttpResponse # Create your views here. static_base = 'http://127.0.0.1:8000' static_url = static_base + settings.MEDIA_URL # 上传文件展示路径前缀 # 上传图片 POST @csrf_exempt def upload_img(request): file = request.FILES['file'] data = { 'error':True, 'path':'', } if file: timenow = int(time.time()*1000) timenow = str(timenow) try: img = Image.open(file) img.save(settings.MEDIA_ROOT + "content/" + timenow + unicode(str(file))) except Exception,e: print e return HttpResponse(json.dumps(data), content_type="application/json") imgUrl = static_url + 'content/' + timenow + str(file) data['error'] = False data['path'] = imgUrl return HttpResponse(json.dumps(data), content_type="application/json")
创建接收上传的文件的文件夹,按照settings.py中的配置和指定的上传文件目录:
其中为了防止回显的时候不识别media路径,在urlpatterns中添加如下:
from django.conf.urls import url from django.contrib import admin from app import views from django.conf import settings from django.conf.urls.static import static urlpatterns = [ url(r'^upload_img/$', views.upload_img), # 后台富文本框上传图片 url(r'^admin/', admin.site.urls), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
目前功能已经全部实现,可以看见上传图片成功之后回显:
顺便附上settings.py中的上传文件和静态文件目录的配置:
# Internationalization # https://docs.djangoproject.com/en/1.10/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/1.8/howto/static-files/ STATIC_URL = '/static/' # 当运行 python manage.py collectstatic 的时候 # STATIC_ROOT 文件夹 是用来将所有STATICFILES_DIRS中所有文件夹中的文件,以及各app中static中的文件都复制过来 # 把这些文件放到一起是为了用apache等部署的时候更方便 STATIC_ROOT = os.path.join(BASE_DIR, 'collected_static') # 其它 存放静态文件的文件夹,可以用来存放项目中公用的静态文件,里面不能包含 STATIC_ROOT # 如果不想用 STATICFILES_DIRS 可以不用,都放在 app 里的 static 中也可以 STATICFILES_DIRS = ( os.path.join(BASE_DIR, "common_static"), ) # 这个是默认设置,Django 默认会在 STATICFILES_DIRS中的文件夹 和 各app下的static文件夹中找文件 # 注意有先后顺序,找到了就不再继续找了 STATICFILES_FINDERS = ( "django.contrib.staticfiles.finders.FileSystemFinder", "django.contrib.staticfiles.finders.AppDirectoriesFinder" ) ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/' MEDIA_URL = '/media/' MEDIA_ROOT = BASE_DIR + '/media/upload/'