关于本站
1、基于Django+Bootstrap开发
2、主要发表本人的技术原创博客
3、本站于 2015-12-01 开始建站
我不会说我前面写的90多篇博文都是通过百度的UEditor官网给出的实例,在上面书写完成之后,再把对应的html代码复制到后台新增博客。
刚开始有些不习惯,后来熟悉了就没先开发富文本编辑器的功能。
但始终多少都有些不方便,例如上传图片,我要先把图片放到响应的位置,再手写img标签的地址。而这个UEditor编辑器直接粘贴就行了。
所以,前面我就先开发UEditor编辑器,将其集成为1个Django应用。
开发富文本编辑器功能,可以新增修改等功能通过富文本编辑器,快速写博文。我将其拆分以下几个步骤:
这个在前面已经有详细讲解,可以参考Django集成UEditor (封装成应用)。
遵循我前面提成的流程:先前端,再后端,最后反馈前端。
大致页面设计成如下效果:

这里我打算采用ajax提交数据。因为一旦发送错误,可以将错误异步传过页面,不用刷新页面。可以保留写入的大量博文内容。
相关的模版代码如下:
{% extends "blog/index.html" %}
{% block blog_head %}
<script type="text/javascript" src="/ueditor/UE/ueditor.config.js"></script>
<script type="text/javascript" src="/ueditor/UE/ueditor.all.min.js"></script>
<script type="text/javascript" src="/ueditor/UE/lang/zh-cn/zh-cn.js"></script>
<script type="text/javascript">
var ue = UE.getEditor('editor');
</script>
{% endblock %}
{% block blog_content%}
<form id="blog_form" action="" methord="POST">
{% csrf_token %}
<div class="input-group">
<span id="blog_title_label" class="input-group-addon">博文标题</span>
<input id="blog_title" name="blog_title" type="text" class="form-control" placeholder="请写入不超过50个字符的标题">
</div>
<div class="input-group">
<span id="tag-list-label" class="input-group-addon">分类标签</span>
<div class="tag-list">
<ul style="overflow: hidden;">
<li class="tag-recommend">
<input id="recommend" type="checkbox" name="recommend" />
<label for="recommend">推荐</label>
</li>
{% for tag in tags %}
<li>
<input id="tag_{{tag.id}}" type="checkbox" name="tag" value="{{tag.id}}" />
<label for="tag_{{tag.id}}">{{tag.tag_name}}</label>
</li>
{% endfor %}
</ul>
</div>
<div class="clearfix"></div>
</div>
<!--用于提交UEditor内容-->
<input id="content" name="content" type="hidden">
</form>
<div style="min-height:600px">
<script id="editor" type="text/plain" style="width:100%;height:500px;"></script>
</div>
<div style="text-align:right;">
<span class="tip-text"></span>
<a id="blog_submit" class="btn btn-primary" href="javascript:void(0);">发表博客</a>
</div>
{% endblock %}此处要注意:
1)UEditor的加载,看第9行代码;
2)form表单有3个字段:博客标题(blog_title)、分类标签(blog_tags)、正文内容(content);
3)为了方便提交数据,正文内容字段是一个hidden类型的input标签。提交数据之前,先把UEditor的内容赋值给这个标签;
4)分类标签,即代码中的tags。我采用复选框的形式。该这段是多对多ManyToMany类型,后面处理有些细节会和大家讲解;
5)因为是POST提交(POST提交可以提交很多数据),需要加上{% csrf_token %}。
页面大致设计完成之后,就开始写前端页面提交处理操作。给提交按钮绑定点击事件。
$("#blog_submit").click(function(){
//检查数据
if(!check_data()) return false;
//.tip_text是一个span标签,用于显示提示内容
$('.tip-text').text('发表博客中...');
//把UEditor内容写入hidden中
var ue = UE.getEditor('editor');
$('#content').val(ue.getContent());
//ajax提交表单
//该部分代码后面补上。
});
//检查数据
function check_data(){
$('.tip-text').text('');
//标题
var title = $('#blog_title').val();
if(title.length<=0 || title.lenght>=50){
$('.tip-text').text('请输入一个不超过50个字符的标题');
return false;
}
//类别
if($('input[name=tag]:checked').length==0){
$('.tip-text').text('请选择除了“推荐”之外的至少1个分类');
return false;
}
//内容
if (!UE.getEditor('editor').hasContents()){
$('.tip-text').text('尚未写入任何博文内容');
return false;
}
return true;
}一般把验证数据是否正确的功能需要在前端页面检查,减少服务器的负担。
这里涉及到UEditor编辑器两个方法:hasContents和getContent,分别是判断是否有内容和获取内容。该部分代码比较简单。
除了ajax的代码未写上,可以先测试检查数据的代码可否正常运行。测试通过之后,再开发后端的代码。
先写个路由设置,可以让我们打开这个新增博客的页面。打开博客应用的views.py文件,加入如下方法:
def add(request):
data= {}
data['tags'] = Tag.objects.all()
return render_to_response('blog/blog_add.html', data, context_instance=RequestContext(request))这里需要全部分类标签,我的分类标签模型名称是Tag。另外第3个参数context_instance是csrf认证需要的。
然后,再添加url路由设置:
url(r'^blog_add$', 'blog.views.add', name='blog_add'),
你可能会有个想法,是不是所有人都可以访问这个页面。那不是很危险?
是的,没做任何处理的话,所有人都可以访问这个页面。
那么,我们需要判断访问者的是否是有权限打开这个页面。我的博客发表博文只允许我自己可以打开,即判断是否是管理员即可。
添加如下装饰器:
#装饰器,管理员判断
def check_admin(func):
def wrapper(request):
if request.user.is_authenticated():
if request.user.is_superuser:
return func(request)
data = {}
data['goto_url'] = '/'
data['goto_time'] = 3000
data['goto_page'] = True
data['message'] = u'您不是管理员,不能进入这个页面'
return render_to_response('message.html',data)
return wrapper此处的message.html是我网站通用的消息提示页面。若判断登录的用户不是管理员,则提醒不能进入该页面。
有了这个装饰器之后,再给这个add方法,加上装饰器即可:
@check_admin
def add(request):
data= {}
data['tags'] = Tag.objects.all()
return render_to_response('blog/blog_add.html', data, context_instance=RequestContext(request))添加views视图和urls设置之后,可以打开前面设计的前端页面测试。
前端页面准备用ajax提交,这个对后端而言还是一个POST提交的Form表单。那么直接在views.py中写blog新增的方法:
#coding:utf-8
from django.shortcuts import render_to_response
from django.http import HttpResponse
from django.core.urlresolvers import reverse #url逆向解析
from blog.models import Blog, Tag, Author #我博客相关的模型
@check_admin
def add_ajax(request):
data = {}
try:
if request.method != 'POST':
raise Exception('method error')
#获取数据
#这些相关数据都是前端页面表单中的字段
#且和我博客模型一一对应,你根据实际情况修改即可
blog_title = request.POST.get('blog_title') #获取标题
blog_tags = request.POST.getlist('tag') #获取分类标签的列表
blog_recommend = request.POST.get('recommend', False) #是否推荐
blog_content = request.POST.get('content') #获取正文内容
#处理tags
tag_ids = []
for tag in blog_tags:
try:
#把文本型的数字,转为数值
tag_id = int(tag)
tag_ids.append(tag_id)
except:
pass
#验证数据(前端页面是不安全的,后端也需要再验证一次)
if len(blog_title) <=0 or len(blog_title)>=50:
raise Exception(u'请输入一个不超过50个字符的标题')
if len(tag_ids)<1:
raise Exception(u'请选择除了“推荐”之外的至少1个类别')
if len(blog_content)==0:
raise Exception(u'尚未写入任何博文内容')
#新增博文
blog = Blog()
blog.caption = blog_title #标题
#这里后面我还要修改,统一用Django的用户系统
#Author是一个作者模型
blog.author = Author.objects.all()[0]
blog.content = blog_content #博客内容
blog.recommend = blog_recommend #是否推荐
blog.save()
#处理多对多,需要博文保存后才能处理,且新增后无需使用save方法
for tag in Tag.objects.filter(id__in = tag_ids):
blog.tags.add(tag)
#返回结果
data['success'] = True
data['message'] = reverse('detailblog', args = [blog.id,])
except Exception as e:
data['success'] = False
data['message'] = e.message
return HttpResponse(json.dumps(data), content_type = 'application/json')这里需要注意的有两个地方:
1)这里返回的json有两个属性:success,标记是否成功;message,附带的消息。若不成功,返回错误信息,若成功,返回对应的博客网址。
2)在我的博客模型值,tags字段是一个ManyToMany类型的字段,它需要Blog保存之后,才能编辑。且编辑之后无需save操作,自动保存。
最后,在url路由添加,这个处理提交数据的链接设置:
url(r'^blog_add_ajax$', 'blog.views.add_ajax', name='blog_add_ajax'),
4、后端开发完成之后,反馈前端
这里前端还需要添加ajax部分的代码。在检验数据之后,继续执行ajax提交的代码:
//ajax提交表单
$.ajax({
type: "POST",
data: $('#blog_form').serialize(),
url: "{% url 'blog_add_ajax' %}",
cache: false,
dataType: "json",
success: function(json, textStatus) {
if(json['success']){
//跳转页面
$('.tip-text').text('发表博文成功,跳转页面中...');
var url = json['message'];
window.location.href = url;
}else{
//显示错误信息
$('.tip-text').text('发表博客出错:'+json['message']);
}
},
error: function (XMLHttpRequest, textStatus, errorThrown) {
$('.tip-text').text('发表博客出错,请检查或稍后再试');
}
});此处,判断返回的json数据。json['success']若为false,说明处理有误,没有新增博客;若为true,则说明新增成功,打开对应博文链接。