我的网站搭建(第35天) 用UEditor新增博文

  • 发布时间:2016年11月28日 17:16
  • 作者:杨仕航
* 该文是基于Python2.7开发的,最新Python3.x和Django2.x视频教程可以前往 >> Django2.0视频教程

我不会说我前面写的90多篇博文都是通过百度的UEditor官网给出的实例,在上面书写完成之后,再把对应的html代码复制到后台新增博客。

刚开始有些不习惯,后来熟悉了就没先开发富文本编辑器的功能。

但始终多少都有些不方便,例如上传图片,我要先把图片放到响应的位置,再手写img标签的地址。而这个UEditor编辑器直接粘贴就行了。

所以,前面我就先开发UEditor编辑器,将其集成为1个Django应用。


开发富文本编辑器功能,可以新增修改等功能通过富文本编辑器,快速写博文。我将其拆分以下几个步骤:

1、Django集成UEditor

这个在前面已经有详细讲解,可以参考Django集成UEditor (封装成应用)


2、前端页面设计

遵循我前面提成的流程:先前端,再后端,最后反馈前端。

大致页面设计成如下效果:

这里我打算采用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的代码未写上,可以先测试检查数据的代码可否正常运行。测试通过之后,再开发后端的代码。


3、后端代码处理提交的数据

先写个路由设置,可以让我们打开这个新增博客的页面。打开博客应用的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,则说明新增成功,打开对应博文链接。

上一篇:vba正则表达式入门

下一篇:Python按位运算

评论列表

智慧如你,不想发表一下意见吗?

新的评论

清空