关于本站
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,则说明新增成功,打开对应博文链接。