KindEditor的简单了解

http://www.cnblogs.com/wupeiqi/articles/6307554.html

简单使用:

<div class="comm">
<form method="POST" enctype="multipart/form-data">
{% csrf_token %}
<div style="margin: 0 auto;" class="comment-area">
<div class="model {% if req.session.user_info %} hide {% endif %}">
您需要登录后才可以回帖 <a href="/login.html">登录</a> | <a href="/register.html">立即注册</a>
</div>
<textarea name="content" id="content"></textarea>
</div>
<div class="comment-sub">
<span>已输入23/</span>
<button type="button" class="btn btn-primary btn-sm" {% if not req.session.user_info %} disabled="disabled" {% endif %}>提交回复</button>
</div>
</form>
</div>

HTML前端

    <script>
$(function () {
initKindEditor();
}); function initKindEditor() {
var kind = KindEditor.create('#content', {
width: '100%', // 文本框宽度(可以百分比或像素)
height: '300px', // 文本框高度(只能像素)
resizeType:,    //不允许修改大小
uploadJson: '/uploadfile.html', //文件上传路径
extraFileUploadParams: { //文件上传的额外参数
'csrfmiddlewaretoken': '{{ csrf_token }}'  //令牌使用,在POST数据上传时需要的
},
//filePostName:'img', 修改上传的文件名字,默认是imgFile
//fileManagerJson: '/kind/file_manager/', //指定浏览远程图片的服务器端程序。
allowPreviewEmoticons: true, //预览表情
allowImageUpload: true, //允许图片上传
items: [
'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
'insertunorderedlist', '|', 'emoticons', 'image', 'link'] //编辑样式选择
});
}
</script>

更多参数了解: http://kindeditor.net/docs/option.html

KindEditor的图片上传(临时目录):

                uploadJson: '/uploadfile.html', //文件上传路径
extraFileUploadParams: { //文件上传的额外参数
'csrfmiddlewaretoken': '{{ csrf_token }}' //令牌使用,在POST数据上传时需要的
},
//filePostName:'img', 修改上传的文件名字

这3个和图片上传有关(了解)

后台处理:

settings配置:

MEDIA_URL = '/static/uploads/'
MEDIA_ROOT=os.path.join(BASE_DIR, 'static/uploads') #注意使用路径连接时后面的必须是相对路径 IMAGE_FIELDS = (
'jpeg',
'png',
'gif',
'jpg',
'bmp',
)
>>> os.path.join("c:/mypy/","/da/dwa")
'c:/da/dwa'
>>> os.path.join("c:/mypy/","da/dwa")
'c:/mypy/da/dwa' 注意后面不能写成绝对路径,不然路径连接时会出错(可以想下linux等系统,不分盘符,'/'就是根路径),所以我们注意这里

补充os.path.join,路径拼接

url设置:

    url(r'^uploadfile.html$',home.uploadFile,{"document_root": settings.MEDIA_ROOT,'web_root':settings.MEDIA_URL,'image_list':settings.IMAGE_FIELDS}),

文件上传处理业务:

def handle_uploaded_file(fp,filePath,webPath,filename):  //fp文件指针,filepath是我们存放文件的基础目录, webpath是我们网站访问该图片的目录,filename是文件名
if not os.path.exists(filePath):
os.makedirs(filePath)
with open(filePath+filename,'wb+') as destination:
for chunk in fp.chunks():
destination.write(chunk)      //写入文件
return webPath+filename  //返回web访问的文件路径 def uploadFile(req,*args,**kwargs):
if req.method != "POST":
return redirect('/')
status = {
'error': ,
'url': '',
'message': ''
}
if req.FILES['imgFile']:
file_name = str(req.FILES.get("imgFile"))
from blog import settings
if file_name.split('.')[-] in kwargs['image_list']:
#先上传到临时文件夹中,然后在与用户提交的评论进行正则匹配,若是匹配到的数据,则移动到正常文件夹中,剩余的图片(用户在编辑时自己删除了的)我们清空该文件夹,并替换用户的图片路径即可
#static_path = "comment/"+str(datetime.date.today())+'/'
static_path = "temp/"+str(req.session['user_info']['id'])+'/' #以用户id为文件名的临时文件夹
web_path = kwargs['web_root'] + static_path
file_path = kwargs['document_root']+'/'+ static_path
ret = handle_uploaded_file(req.FILES['imgFile'],file_path,web_path,file_name)
status['url'] = ret
else:
status['error']=
status['message']="文件格式不正确"
else:
status['error'] =
status['message'] = "文件上传失败"
return HttpResponse(json.dumps(status))

KindEditor的图片处理思路:

为用户先创立一个临时文件夹,在用户上传评论时,与img标签进行正则匹配,若是匹配到的数据,我们则移入到正确的路径,然后将临时文件夹删除即可。

其他思路可以参考:

http://kindeditor.net/view.php?bbsid=5&postid=6049

基本上2种解决方案:

. 先把图片提交到临时目录,提交到服务器后,用正则提取图片路径,和上传过的图片比较,如果用到就把图片移动到实际目录。

. 采用图片空间管理,让用户自己删除多余的图片,一个用户的总容量限制就可以了,现在很多大网站都是这个做法。

或者:前端使用ajax进行删除,但是如果用户可以进行撤销操作,那么原来的图片使用ajax似乎不太正确:

http://kindeditor.net/view.php?bbsid=7&postid=6834&pagenum=1

大概思路:

可以知道数据是使用iframe进行传输的:iframe无刷新上传文件:http://www.cnblogs.com/ssyfj/p/8533287.html(了解)

我们可以操作该对象,对img点击事件进行监听

$(".ke-edit-iframe")    //获取iframe对象

obj = $(".ke-edit-iframe") .contents()    //获取iframe中的document对象

$(obj).find("img")  //获取img元素对象,使用click等就可以进行监听,使用户点击使进行删除选项,同意则使用ajax进行删除

KindEditor的图片上传实现:

前端js

        $(function () {
var Ke = new KindEdit_Class();
Ke.initKindEditor(); $(".btn_sub_comm").click(function(){
Ke.submitData();
})
});

$(function(){...});

    function KindEdit_Class(){
this.kind = null; this.initKindEditor = function () {
this.kind = KindEditor.create('#content', {
width: '100%', // 文本框宽度(可以百分比或像素)
height: '300px', // 文本框高度(只能像素)
resizeType:,
uploadJson: '/uploadfile.html', //文件上传路径
extraFileUploadParams: { //文件上传的额外参数
'csrfmiddlewaretoken': '{{ csrf_token }}'
},
//filePostName:'img', 修改上传的文件名字
//fileManagerJson: '/kind/file_manager/', //指定浏览远程图片的服务器端程序。
allowPreviewEmoticons: true, //预览表情
allowImageUpload: true, //允许图片上传
items: [
'fontname', 'fontsize', '|', 'forecolor', 'hilitecolor', 'bold', 'italic', 'underline',
'removeformat', '|', 'justifyleft', 'justifycenter', 'justifyright', 'insertorderedlist',
'insertunorderedlist', '|', 'emoticons', 'image', 'link']
});
} this.submitData = function(){
this.kind.sync();//将KindEditor的数据同步到textarea标签。 if($("#content").text().trim() == ""){
alert("请填写内容")
return;
} var that=this
$.ajax({
url:"/submitComment.html",
data:$("#fm").serialize(),
dataType:"json",
type:"POST",
success:function(data){
if(!data.error){
{#alert(data.message)#}
{#that.kind.html("")#}
{#$("#content").text("")#} location.href=""
}
}
})
}
}

function KindEdit_Class(){...}

后台图片处理:

    url(r'^uploadfile.html$',home.uploadFile,{"document_root": settings.MEDIA_ROOT,'web_root':settings.MEDIA_URL,'image_list':settings.IMAGE_FIELDS}),
url(r'^submitComment.html$',home.comment,{"base_dir": settings.BASE_DIR,'web_root':settings.MEDIA_URL,"document_root": settings.MEDIA_ROOT}),

url

import datetime,json,os
from utils import CustomXss
from repository.Model import CommentModel as CmModels
from web.form.comment import CommentForm

部分模块导入

1.图片上传到临时文件夹:

def handle_uploaded_file(fp,filePath,webPath,filename):
if not os.path.exists(filePath):
os.makedirs(filePath)
with open(filePath+filename,'wb+') as destination:
for chunk in fp.chunks():
destination.write(chunk)
return webPath+filename

def handle_uploaded_file(fp,filePath,webPath,filename) 图片保存

def uploadFile(req,*args,**kwargs):
if req.method != "POST":
return redirect('/')
status = {
'error': ,
'url': '',
'message': ''
}
if req.FILES['imgFile']:
file_name = str(req.FILES.get("imgFile"))
from blog import settings
if file_name.split('.')[-] in kwargs['image_list']:
#先上传到临时文件夹中
#static_path = "comment/"+str(datetime.date.today())+'/'
static_path = "temp/"+str(req.session['user_info']['id'])+'/' #以用户id为文件名的临时文件夹
web_path = kwargs['web_root'] + static_path
file_path = kwargs['document_root']+'/'+ static_path
ret = handle_uploaded_file(req.FILES['imgFile'],file_path,web_path,file_name)
status['url'] = ret
else:
status['error']=
status['message']="文件格式不正确"
else:
status['error'] =
status['message'] = "文件上传失败"
return HttpResponse(json.dumps(status))

def uploadFile(req,*args,**kwargs) 获取图片信息,进行处理后返回json数据

2.用户提交数据后处理数据:

def comment(req,*args,**kwargs):
if req.method=="GET":
return redirect('/')
form = CommentForm({'comment':req.POST['content'],})
status = {
'error':,
'message':"回复成功",
}
if not form.is_valid():
status['error']=
status['message']="评论字数过长"
return HttpResponse(json.dumps(status)) Xss = CustomXss.XSSFilter(**{'content':req.POST['content']}) #要移动到的目录
moveToDir = kwargs['document_root'] + '/' +"comment/" + str(datetime.date.today()) + '/'
#网站根目录
baseDir = kwargs['base_dir']
#网站相对目录
webPath = kwargs['web_root'] + moveToDir #临时文件夹目录
static_path = "temp/" + str(req.session['user_info']['id']) + '/'
tempDir = kwargs['document_root'] + '/' + static_path #修改img标签src属性,并且移动图片路径 临时文件夹---->固定目录
Xss.clean_img(**{'baseDir':baseDir,"moveToDir":moveToDir,'webDir':webPath,'tempDir':tempDir}) #获取到了img src列表 #XSS过滤
content = Xss.process() # 获取到了用户的评论数据 #模型添加评论数据:
models = CmModels.CommentModel()
models.add(**{'art_id_id':int(req.POST['art_id']),'user_id_id':int(req.session['user_info']['id']),'comment':content,'parent_id':int(req.POST.get("parent_id",))}) return HttpResponse(json.dumps(status))
from repository import models

class CommentModel(object):
comment = None
model = None Insert_Fields = ['art_id_id','user_id_id','ctime','parent_id','comment']
# Update_Fields = ['theme','title','summary',] 评论不允许修改 def __new__(cls, *args, **kwargs):
if not cls.comment:
cls.comment = super(CommentModel,cls).__new__(cls)
return cls.comment def __init__(self):
if CommentModel.model is None:
CommentModel.model = models.Comment.objects def add(self,**where):
data = {}
for item in where.keys():
if item in self.Insert_Fields:
data[item]=where[item]
ret = CommentModel.model.create(
**data
)
return ret def search(self,**where):
data = CommentModel.model.filter(**where).all()
return data

CommentModel

   
补充:http://python.jobbole.com/86506/
    # __new__: 对象的创建,是一个静态方法,第一个参数是cls。(想想也是,不可能是self,对象还没创建,哪来的self)
# __init__ : 对象的初始化, 是一个实例方法,第一个参数是self。
# __call__ : 对象可call,注意不是类,是对象。
# 先有创建,才有初始化。即先__new__,而后__init__。 http://www.jb51.net/article/85719.htm
下面进行图片处理,将临时文件夹中的图片移动到固定目录,其余多余图片进行删除
from bs4 import BeautifulSoup
import shutil,os #单例模式实现
class XSSFilter(object):
__instance = None #__开头是私有成员,为了不让用户在外面直接访问,将变量进行了重新命名将__spam修改为_classname__spam,导致用户在外面是无法使用__spam的,但是用户一定要使用,那么可以使用替换后的名字_className__spam def __new__(cls, *args, **kwargs): #http://python.jobbole.com/86506/
if not cls.__instance:
obj = object.__new__(cls) #父类执行,创建对象
cls.__instance = obj
return cls.__instance def __init__(self,*args,**kwargs):
# XSS白名单
self.valid_tags = {
"font": ['color', 'size', 'face', 'style'],
'b': [],
'div': [],
"span": [],
"table": [
'border', 'cellspacing', 'cellpadding'
],
'th': [
'colspan', 'rowspan'
],
'td': [
'colspan', 'rowspan'
],
"a": ['href', 'target', 'name'],
"img": ['src', 'alt', 'title','height','width'],
'p': [
'align'
],
"pre": ['class'],
"hr": ['class'],
'strong': []
} self.soup = BeautifulSoup(kwargs['content'], 'lxml') # https://blog.csdn.net/kikaylee/article/details/56841789 #进行数据处理
def process(self):
#遍历所有节点
for tag in self.soup.find_all(recursive=True): #遍历所有子孙节点
if tag.name not in self.valid_tags:
tag.hidden = True
if tag.name not in ['html', 'body']:
tag.hidden = True
tag.clear() #清除该节点
continue attr_rules = self.valid_tags[tag.name]
keys = list(tag.attrs.keys())
for key in keys:
if key not in attr_rules:
del tag[key] return self.soup.renderContents() def clean_data(self,*args,**kwargs):
'''
回调函数,
用户进行扩展
'''
pass def clean_img(self,*args,**kwargs):
'''
回调函数,
用户进行扩展
#baseDir, 要移动到绝对目录(项目根目录)
#moveToDir 要移动到的固定目录
#webDir 前端显示时需要的相对目录
#tempDir 临时文件夹目录
'''
# 这里就直接写在这里,不在进行继承调用了
move_dir = kwargs['moveToDir'] #移动的目录路径
temp_dir = kwargs['tempDir'] #临时文件夹 if not os.path.isdir(temp_dir):
return if not os.path.isdir(move_dir):
os.makedirs(move_dir) #处理img的src属性
for tag in self.soup.find_all('img'): # 遍历所有图片节点
src = tag.attrs['src']
root_dir = kwargs['baseDir']+src #文件路径
print(root_dir,move_dir)
shutil.move(root_dir,move_dir)
tag.attrs['src'] = kwargs['webDir']+src.split('/')[-] #删除临时文件夹
shutil.rmtree(temp_dir)

单例模式实现xss过滤,以及图片数据处理(重点)

BeautifulSoup了解(最主要的功能是从网页抓取数据)

Beautiful Soup提供一些简单的、python式的函数用来处理导航、搜索、修改分析树等功能。它是一个工具箱,通过解析文档为用户提供需要抓取的数据,因为简单,所以不需要多少代码就可以写出一个完整的应用程序。
Beautiful Soup自动将输入文档转换为Unicode编码,输出文档转换为utf-8编码。你不需要考虑编码方式,除非文档没有指定一个编码方式,这时,Beautiful Soup就不能自动识别编码方式了。然后,你仅仅需要说明一下原始编码方式就可以了。
Beautiful Soup已成为和lxml、html6lib一样出色的python解释器,为用户灵活地提供不同的解析策略或强劲的速度

Beautiful Soup简介

shutil模块了解(文件和文件夹进行移动、复制、删除、重命名,主要依赖os模块和shutil模块)

KindEditor的简单使用,以及上传图片预览图片,用户删除图片后的数据处理(重点),以及 BeautifulSoup,shutil两模块了解的更多相关文章

  1. 简单实现JS上传图片预览功能

    HTML代码 <div class="upload"> <input type="button" class="btn" ...

  2. HTML5上传图片预览

    <!DOCTYPE html> <html> <head> <title>HTML5上传图片预览</title> <meta http ...

  3. jquery实现上传图片预览(需要浏览器支持html5)

    jquery实现上传图片预览(需要浏览器支持html5) <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN&q ...

  4. HTML5上传图片预览功能

    HTML5上传图片预览功能 HTML代码如下: <!-- date: 2018-04-27 14:41:35 author: 王召波 descride: HTML5上传图片预览功能 --> ...

  5. JS 上传图片 + 预览功能(一)

    JS 上传图片 + 预览功能 <body> <input type="file" id="fileimg1" style="disp ...

  6. js兼容火狐显示上传图片预览效果

    js兼容火狐显示上传图片预览效果[谷歌也适用] <!doctype html> <html> <head> <meta content="text/ ...

  7. 通过HTML5 FileReader实现上传图片预览功能

    原文:http://www.htmleaf.com/ziliaoku/qianduanjiaocheng/201706224590.html 在上传图片到服务器之前,我们希望可以预览一下要上传的图片. ...

  8. 去除ckeditor上传图片预览中的英文字母

    去除ckeditor上传图片预览中的英文字母 CKEDITOR.replace('text', { filebrowserImageUploadUrl : 'upload_img.do', langu ...

  9. HTML5 上传图片预览

    html5出现之前如果需要上传图片预览 一般都是先上传到服务器然后远程预览 html5出现之后   有个filereader 解决了这问题 //选中图片之后 $("#fileAddPic&q ...

随机推荐

  1. django请求的生命周期

    1. 概述 首先我们知道HTTP请求及服务端响应中传输的所有数据都是字符串. 在Django中,当我们访问一个的url时,会通过路由匹配进入相应的html网页中. Django的请求生命周期是指当用户 ...

  2. R绘图 第八篇:绘制饼图(ggplot2)

    geom_bar()函数不仅可以绘制条形图,还能绘制饼图,跟绘制条形图的区别是坐标系不同,绘制饼图使用的坐标系polar,并且设置theta="y": coord_polar(th ...

  3. R实战 第八篇:重塑数据(reshape2)

    数据重塑通常使用reshape2包,reshape2包用于实现对宽数据及长数据之间的相互转换,由于reshape2包不在R的默认安装包列表中,在第一次使用之前,需要安装和引用: install.pac ...

  4. Azure SQL Database Active Geo-Replication 简介

    对于数据库的维护来说,备份工作可谓是重中之重.MS Azure 当然也提供了很完善的数据库备份功能.但是在动手创建备份计划前请思考一下备份工作的真实目的.当然首先要保证数据的安全,一般来说定时创建数据 ...

  5. 我用Python爬虫挣钱的那些事

    在下写了10年Python,期间写了各种奇葩爬虫,挣各种奇葩的钱,写这篇文章总结下几种爬虫挣钱的方式. 1.最典型的就是找爬虫外包活儿. 这个真是体力活,最早是在国外各个freelancer网站上找适 ...

  6. 原生js实现table的排序

    原生js实现table的排序 今天遇到了一个问题就是使用原生js对table标签进行排序 一开始的时候陷入了一个误区就是首先获取table,然后每次比较完大小都会交换children的值,准备到最后吧 ...

  7. 学习笔记 | CDQ分治

    目录 前言 啥是CDQ啊(它的基本思想) 例题 后记 参考博文 前言 博主太菜了 学习快一年的OI了 好像没有什么会的算法 更寒碜的是 学一样还不精一样TAT 如有什么错误请各位路过的大佬指出啊感谢! ...

  8. Beta阶段展示博客

    Beta阶段展示博客 1. 团队成员的简介和个人博客地址 刘畅 博客园ID:森高Slontia 身份:PM 个人介绍: 弹丸粉 || 小说创作爱好者 || 撸猫狂魔(x || 生命的价值在于创造 (我 ...

  9. es6箭头函数使用场景导致的一些问题

    1. 今天在使用draggable组件时,监听dragmove事件时获取到的事件对象有一些异常, 代码如下 draggable.on('drag:move', (event) => { cons ...

  10. PAT甲题题解-1034. Head of a Gang (30)-并查集

    给出n和k接下来n行,每行给出a,b,c,表示a和b之间的关系度,表明他们属于同一个帮派一个帮派由>2个人组成,且总关系度必须大于k.帮派的头目为帮派里关系度最高的人.(注意,这里关系度是看帮派 ...