一、DjangoUeditor
1、概述
富文本编辑器,在web开发中可以说是不可缺少的 ,但是django并没有自带富文本编辑器,因此我们需要使用第三方库,这里使用DjangoUeditor。
DjangoUeditor是百度开源的在线HTML编辑器,功能非常强大,像表格可以直接拖动调整单元格大小等
2、安装
该库存在bug,需要修改源码文件,因此使用源文件安装
1.新建项目
创建需要使用DjangoUeditor的django项目
2.下载
从github下载源码进行安装: https://github.com/twz915/DjangoUeditor3/,下载后解压,在解压后的文件夹中有一个 DjangoUeditor 文件夹,我们后续需要使用到
3.项目中添加库
- 在项目根目录下新建 extra_apps 文件夹
- 在 extra_apps 文件夹上依次 右键 >>Mark Directory as>>Sources Root,设置为项目资源文件夹
- 将第二步解压出来的文件夹中的 DjangoUeditor 目录拷贝到 extra_apps
- 在项目的 settings 中增加以下代码:
python sys.path.insert(0, os.path.join(BASE_DIR, 'extra_apps'))
3.应用
1.settings
INSTALLED_APPS = [
# ......
'DjangoUeditor',
]
2.根urls
urlpatterns = [
# ......
path('ueditor/', include('DjangoUeditor.urls')),
]
3.UEditorField
UEditorField继承自models.TextField,因此可以直接将model里面定义的models.TextField直接改成UEditorField即可。
定义UEditorField时除了可以直接传入models.TextField提供的参数外,还可以传入UEditorField提供的额外的参数来控制UEditorField的外观、上传路径等。
UEditorField的参数如下:
- width,height :编辑器的宽度和高度,以像素为单位。
- toolbars :配置你想显示的工具栏,取值为mini,normal,full,代表小,一般,全部。如果默认的工具栏的按钮数量不符合您的要求,您可以在settings里面配置自己的显示按钮。参见后面介绍。
- imagePath :图片上传后保存的路径,如"images/",实现上传到"{{MEDIA_ROOT}}/images"文件夹。 注意:如果imagePath值只设置文件夹,则未尾要有"/" imagePath可以按python字符串格式化:如"images/%(basename)s_%(datetime)s_%(rnd)s.%(extname)s"。这样如果上传test.png,则文件会 被保存为"{{MEDIA_ROOT}}/images/test_20140625122399_259.png"。 imagePath中可以使用的变量有:
- time :上传时的时间,datetime.datetime.now().strftime("%H%M%S")
- date :上传时的日期,datetime.datetime.now().strftime("%Y%m%d")
- datetime :上传时的时间和日期,datetime.datetime.now().strftime("%Y%m%d%H%M%S")
- year : 年
- month : 月
- day : 日
- rnd : 三位随机数,random.randrange(100,999)
- basename : 上传的文件名称,不包括扩展名
- extname : 上传的文件扩展名
- filename : 上传的文件名全称
- filePath : 附件上传后保存的路径,设置规则与imagePath一样。
- upload_settings : 字典值, 例:upload_settings={ imagePathFormat:"images/%(basename)s_%(datetime)s.%(extname)s", imageMaxSize:323232, fileManagerListPath:"files" }
- upload_settings的内容就是static/ueditor/php/config.json里面的配置内容,因此,你可以去看config.json或者官方文档内容来决定 该如何配置upload_settings,基本上就是用来配置上传的路径、允许上传的文件扩展名、最大上传的文件大小之类的。
- 上面的imagePath和filePath被单独提取出来配置,原因是因为这两个参数是最常使用到的,imagePath就相当于upload_settings里面的 imagePathFormat,filePath就相当于upload_settings里面的filePathFormat。
- upload_settings里面设置了imagePathFormat,也可以在UeditorField里面设置imagePath,效果是一样的。但是如果两者均设置, 则imagePath优先级更高。
- 涂鸦文件、截图、远程抓图、图片库的xxxxPathFormat如果没有配置,默认等于imagePath.
- 远程文件库的xxxxPathFormat如果没有配置,默认等于filePath.
- settings : 字典值,配置项与static/ueditor/ueditor.config.js里面的配置项一致。
- command : 可以为Ueditor新增一个按钮、下拉框、对话框,例:
Description = UEditorField(u'描述', blank=True, toolbars="full", imagePath="cool/", settings={"a": 1},command=[myBtn(uiName="mybtn1", icon="d.png", title="aaa", ajax_url="/ajaxcmd/"),myCombo(uiName="myCombo3",title="ccc",initValue="111")])
command 列表中的按钮是 commands 模块下 UEditorCommand 的实例列表:
UEditorButtonCommand:可以在Ueditor上增加一个按钮
UEditorComboCommand:可以在Ueditor上增加一个下拉框
UEditorDialogCommand:可以在Ueditor上增加一个对话框,暂时未实现
也可以自定义:
from DjangoUeditor.commands import UEditorButtonCommand,UEditorComboCommand
#定义自己的按钮命令类
class myBtn(UEditorButtonCommand):
def onClick(self):
return u"""
alert("爽!"); //这里可以写自己的js代码
editor.execCommand(uiName);
"""
def onExecuteAjaxCommand(self,state):
""" 默认在command代码里面加入一段ajax代码,如果指定了ajax_url和重载本方法,则在单点按钮后
会调用ajax_url.本方法重载是可选的。
"""
if state=="success":
return u"""
alert("后面比较爽!"+xhr.responseText);//这里可以写ajax成功调用的js代码
"""
if state=="error":
return u"""
alert("讨厌,摸哪里去了!"+xhr.responseText);//这里可以写ajax错误调用的js代码
"""
父类UEditorCommand有4个初始化参数:
uiName:按钮名称
title:按钮提示信息
index:按钮显示的位置索引
ajax_url:单击时调用的ajax url
- event_handler : 用来为Ueditor实例绑定事件侦听,比如以下示例的功能是:当选择区改变时将按钮状态设置为禁止:
from DjangoUeditor.commands import UEditorEventHandler
class myEventHander(UEditorEventHandler):
def on_selectionchange(self):
return """
function getButton(btnName){
var items=%(editor)s.ui.toolbars[0].items;
for(item in items){
if(items[item].name==btnName){
return items[item];
}
}
}
var btn=getButton("mybtn1");
var selRanage=id_Description.selection.getRange()
btn.setDisabled(selRanage.startOffset == selRanage.endOffset);
"""
说明:
- 我们可以继承UEditorEventHandler创建自己的事件侦听类,例如上面myEventHander,然后在myEventHander中 增加on_eventname的方法,在里面返回侦听该event的js代码。例如上例on_selectionchange,就会在前端js中 生成id_Description.addListener('selectionchange', function () {.......});
- 如果要侦听contentchange事件,就在myEventHander中增加一个on_contentchange方法,然后在该方法中返回js代码。
4.模型应用
富文本库的使用,都是为了提交带格式的内容,因此一般都应用在模型上,我们新建一个模型:
from DjangoUeditor.models import UEditorField
class Article(models.Model):
title = models.CharField(max_length=100, verbose_name='标题')
create_time = models.DateTimeField(auto_now_add=True, verbose_name='发表时间')
# 富文本字段
content = UEditorField( width=600, height=300, toolbars="full", imagePath="images/", filePath="files/", upload_settings={"imageMaxSize":1204000},
settings={}, verbose_name='内容', blank=True, null=True)
class Meta:
verbose_name_plural = verbose_name = '文章'
说明:
- 应用 UEditorField 字段类
- 别忘记去settings修改时区,TIME_ZONE = 'Asia/Shanghai' 否则写入数据库的时间是 UTC 时间
imagePath
5.执行数据库迁移
配置好settings中的数据库
python manage.py makemigrations
python manage.py migrate
6.使用admin管理模型
admin.py:
admin.site.register(Article)
7.访问admin后台
需要先创建账号:
python manage.py createsuperuser
8.处理图片文件
- settings中:
MEDIA_URL ='/media/'
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
- 在根目录下创建 media 文件夹
- 根urls:
from django.conf import settings
from django.conf.urls.static import static
if settings.DEBUG:
urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
9.模板中应用
使用 ModelForm 使用富文本
首先在子应用中新建forms.py,然后在模块中新增:
class ArticleModelForm(forms.ModelForm):
class Meta:
model = Article
fields = ['title', 'content']
说明:
如果不使用ModelForm,那么在一般的Form类中则使用以下两种方式:
- DjangoUeditor.forms.UEditorField
python class TestUEditorForm(forms.Form): Content=UEditorField("描述",initial="abc",width=600,height=800)
- DjangoUeditor.widgets.UEditorWidget
```python class TestUEditorForm(forms.Form): Content=forms.CharField(label="内容",widget=UEditorWidget(width=800,height=500, imagePath='aa', filePath='bb',toolbars={}))
```
- 显示列表
urls:
path('articles/', views.articles, name='articles'),
templates:新增ueditor_app/articles.html
django <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>文章列表</title> </head> <body> <ul> <li><a href="{% url 'ueditor_app:article' %}">新增文章</a></li> {% for article in articles %} <li>标题:{{ article.title }},创建时间:{{ article.create_time|date:"Y-m-d H:i:s" }}, <a href="{% url 'ueditor_app:article_update' %}?id={{ article.id }}">修改</a></li> {% endfor %} </ul> </body> </html>
views:
python def articles(request): articles = Article.objects.all() return render(request, 'ueditor_app/articles.html', {'articles':articles})
- 新增
urls:
python path('article/', views.article, name='article'), path('article_add/', views.article_add, name='article_add'),
templates:新增ueditor_app/article.html
django <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>新增文章</title> {{ form.media }} </head> <body> <form method="post" action="{% url 'ueditor_app:article_add' %}"> {% csrf_token %} <table> {{ form }} <tr> <td colspan="2"> <input type="submit" value="新增"> </td> </tr> </table> </form> </body> </html>
说明:
- {{ form.media }}:用于导入ueditor必须的js文件
- {{ form }}:用于显示title和content,其中content是ueditor,会自动编写javascript代码,根据content的id进行初始化
views:
```python def article(request): form = ArticleModelForm() return render(request, 'ueditor_app/article.html', {'form': form})
def article_add(request): form = ArticleModelForm(request.POST)
if form.is_valid():
form.save()
return redirect('ueditor_app:articles')
```
- 修改
urls:
path('article_update/', views.article_update, name='article_update'),
templates:新增ueditor_app/article_update.html
django <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>修改文章</title> {{ form.media }} </head> <body> <form method="post" action="{% url 'ueditor_app:article_update' %}"> {% csrf_token %} <input type="hidden" name="id" value="{{ form.instance.id }}"> <table> {{ form }} <tr> <td colspan="2"> <input type="submit" value="修改"> </td> </tr> </table> </form> </body> </html>
views:
```python def article_update(request): if request.method == 'POST': id = request.POST.get('id') article = Article.objects.get(pk=id) form = ArticleModelForm(request.POST, instance=article)
if form.is_valid():
form.save()
return redirect('ueditor_app:articles')
else:
id = request.GET.get('id')
article = Article.objects.get(pk=id)
form = ArticleModelForm(instance=article)
return render(request, 'ueditor_app/article_update.html', {'form': form})
```
10.全局配置
在settings中可以增加全局的配置
UEDITOR_SETTINGS={
"config":{
# 这里放ueditor.config.js里面的配置项
# 和UeditorField类中的 settings 一样配置
},
"upload":{
# 这里放php/config.json里面的配置项,
# 和UeditorField类中的 upload_settings 一样配置
}
}