python 学习 39

django 07

富文本编辑器

富文本编辑器,Rich Text Editor, 简称 RTE, 是一种可内嵌于浏览器,所见即所得的文本编辑器。

UEditor是由百度web前端研发部开发所见即所得富文本web编辑器,具有轻量,可定制,注重用户体验等特点,开源基于MIT协议,允许自由使用和修改代码。

1.首先下载富文本编辑器

下载链接:  http://ueditor.baidu.com/website/download.html#ueditor

这里我们下载完整源码

2.将下载的内容放到django项目中,这里我们放在static文件夹下,新建一个ueditor文件夹,将其放入其中。


3.创建一个html

这里我们使用ueditor下_examples下submitFormDemo.html的模板样式,将b.html修改为

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script type="text/javascript" charset="utf-8" src="/static/ueditor/ueditor.config.js"></script>
    <script type="text/javascript" charset="utf-8" src="/static/ueditor/_examples/editor_api.js"></script>
</head>
<body>
<form id="form" method="post" target="_blank">
    {% csrf_token %}
        <script type="text/plain" id="myEditor" name="myEditor">
            <p>欢迎使用UEditor!</p>
        </script>
        <input type="submit" value="通过input的submit提交">
</form>

<script type="text/javascript">
    var editor_a = UE.getEditor('myEditor',{});
</script>
</body>
</html>

这里需注意将我们导入的script文件修改成我们当前存放的路径

接着我们打开editor_api.js 

将下面baseURL 的路径改为我们当前_src的路径


这一点很重要,它的目的是将这些script文件导入到html里面

3. 视图函数与urls路由

我们将uecontroller.py 放入blog包中。

uecontroller.py:

from django.shortcuts import render , redirect , reverse , HttpResponse
import json
import re

configStr = ""
with open('config.json','r',encoding="utf-8") as jf:
     for line in jf:
         configStr += re.sub(r"/\*(.*)\*/","",line)
print(configStr)
config = json.loads(configStr)
print(config)

from django.http import HttpResponse
import codecs
import json
import os
from django.views.decorators.csrf import csrf_exempt
import random
from datetime import *
import blog.settings as settings

#ROOT = os.path.dirname(__file__)
ROOT = settings.BASE_DIR

#本地上传图片时构造json返回值
class JsonResult(object):
    def __init__(self,state="未知错误",url="",title="",original="",error="null"):
        super(JsonResult,self).__init__()
        self.state = state
        self.url = url
        self.title = title
        self.original = original
        self.error = error

#构造返回json
def buildJsonResult(result):
    jsondata = {"state":result.state,"url":result.url,"title":result.title,"original":result.original,"error":result.error}
    return json.dumps(jsondata)

def buildFileName(filename):
    dt = datetime.now()
    name,ext = os.path.splitext(filename)
    return dt.strftime("%Y%m%d%M%H%S{0}{1}".format(random.randint(1,999999),ext))

#读取json文件
def getConfigContent():
    return config

#上传配置类
class UploadConfig(object):
    def __init__(self,PathFormat,UploadFieldName,SizeLimit,AllowExtensions,SavePath,Base64,Base64Filename):
        super(UploadConfig,self).__init__()
        self.PathFormat = PathFormat
        self.UploadFieldName = UploadFieldName
        self.SizeLimit = SizeLimit
        self.AllowExtensions = AllowExtensions
        self.SavePath = SavePath
        self.Base64 = Base64
        self.Base64Filename = Base64Filename

#获取json配置中的某属性值
def GetConfigValue(key):
    config = getConfigContent()
    return config[key]

#检查文件扩展名是否在允许的扩展名内
def CheckFileType(filename,AllowExtensions):
    exts = list(AllowExtensions)
    name,ext = os.path.splitext(filename)
    return ext in exts

def CheckFileSize(filesize,SizeLimit):
    return filesize<SizeLimit

#处理上传图片、文件、视频文件
@csrf_exempt
def uploadFile(request,config):
    result = JsonResult()
    if config.Base64:
        pass
    else:
        buf = request.FILES.get(config.UploadFieldName)
        filename = buf.name
        if not CheckFileType(filename,config.AllowExtensions):
            result.error =u"不允许的文件格式"
            return HttpResponse(buildJsonResult(result))

        if not CheckFileSize(buf.size,config.SizeLimit):
            result.error = u"文件大小超出服务器限制"
            return HttpResponse(buildJsonResult(result))


        try:
            #重新定义上传图片的名字
            truelyName = buildFileName(filename)
            #
            webUrl = config.SavePath+ truelyName
            print(webUrl)
            #savePath =ROOT+webUrl
            savePath = R'static/uplaod/img/'+ webUrl
            print(savePath)
            f = codecs.open(savePath,"wb")
            for chunk in buf.chunks():
                f.write(chunk)
            f.flush()
            f.close()
            result.state = "SUCCESS"
            #返回富文本显示的图片地址
            result.url = R'/'+savePath#truelyName
            result.title = truelyName
            result.original = truelyName
            response = HttpResponse(buildJsonResult(result))
            response["Content-Type"] = "text/plain"
            return response
        except Exception as e:
            result.error = u"网络错误"
            return HttpResponse(buildJsonResult(result))

#处理在线图片与在线文件
#返回的数据格式:{"state":"SUCCESS","list":[{"url":"upload/image/20140627/6353948647502438222009315.png"},{"url":"upload/image/20140627/6353948659383617789875352.png"},{"url":"upload/image/20140701/6353980733328090063690725.png"},{"url":"upload/image/20140701/6353980745691597223366891.png"},{"url":"upload/image/20140701/6353980747586705613811538.png"},{"url":"upload/image/20140701/6353980823509548151892908.png"}],"start":0,"size":20,"total":6}
def listFileManage(request,imageManagerListPath,imageManagerAllowFiles,listsize):
    pstart = request.GET.get("start")
    start = pstart==None and int(pstart) or 0
    psize = request.GET.get("size")
    size = psize==None and int(GetConfigValue(listsize)) or int(psize)
    localPath = ROOT+imageManagerListPath
    filelist = []
    exts = list(imageManagerAllowFiles)
    index = start
    print(localPath)
    for imagename in os.listdir(localPath):
        name,ext = os.path.splitext(imagename)
        if ext in exts:
            filelist.append(dict(url=imagename))
            index+=1
            if index-start>=size:
                break
    jsondata = {"state":"SUCCESS","list":filelist,"start":start,"size":size,"total":index}
    return HttpResponse(json.dumps(jsondata))



#返回配置信息
def configHandler(request):
    content = getConfigContent()
    callback = request.GET.get("callback")
    if callback:
        return HttpResponse("{0}{1}".format(callback,json.dumps(content)))
    return HttpResponse(json.dumps(content))

#图片上传控制
@csrf_exempt
def uploadimageHandler(request):
    AllowExtensions = GetConfigValue("imageAllowFiles")
    PathFormat = GetConfigValue("imagePathFormat")
    SizeLimit = GetConfigValue("imageMaxSize")
    UploadFieldName = GetConfigValue("imageFieldName")
    SavePath = GetConfigValue("imageUrlPrefix")
    upconfig = UploadConfig(PathFormat,UploadFieldName,SizeLimit,AllowExtensions,SavePath,False,'')
    return uploadFile(request,upconfig)

def uploadvideoHandler(request):
    AllowExtensions = GetConfigValue("videoAllowFiles")
    PathFormat = GetConfigValue("videoPathFormat")
    SizeLimit = GetConfigValue("videoMaxSize")
    UploadFieldName = GetConfigValue("videoFieldName")
    SavePath = GetConfigValue("videoUrlPrefix")
    upconfig = UploadConfig(PathFormat,UploadFieldName,SizeLimit,AllowExtensions,SavePath,False,'')
    return uploadFile(request,upconfig)


def uploadfileHandler(request):
    AllowExtensions = GetConfigValue("fileAllowFiles")
    PathFormat = GetConfigValue("filePathFormat")
    SizeLimit = GetConfigValue("fileMaxSize")
    UploadFieldName = GetConfigValue("fileFieldName")
    SavePath = GetConfigValue("fileUrlPrefix")
    upconfig = UploadConfig(PathFormat,UploadFieldName,SizeLimit,AllowExtensions,SavePath,False,'')
    return uploadFile(request,upconfig)

#在线图片
def listimageHandler(request):
    imageManagerListPath = GetConfigValue("imageManagerListPath")
    imageManagerAllowFiles = GetConfigValue("imageManagerAllowFiles")
    imagelistsize = GetConfigValue("imageManagerListSize")
    return listFileManage(request,imageManagerListPath,imageManagerAllowFiles,imagelistsize)

#在线文件
def ListFileManagerHander(request):
    fileManagerListPath = GetConfigValue("fileManagerListPath")
    fileManagerAllowFiles = GetConfigValue("fileManagerAllowFiles")
    filelistsize = GetConfigValue("fileManagerListSize")
    return listFileManage(request,fileManagerListPath,fileManagerAllowFiles,filelistsize)

actions = {
    "config":configHandler,
    "uploadimage":uploadimageHandler,
    "uploadvideo":uploadvideoHandler,
    "uploadfile":uploadfileHandler,
    "listimage":listimageHandler,
    "listfile":ListFileManagerHander
}

@csrf_exempt
def handler(request):
    action = request.GET.get("action")
    return actions.get(action)(request)

首先将settings的路径修改为django项目的路径


再将b.html中script添加:


然后在blog中的urls中添加一条路径:

#usr/bin/python
#-*-coding:utf-8-*-

app_name='blog'

from django.urls import path
from blog import views
from .uecontroller import handler

urlpatterns = [
    path('saveblog', views.saveblog),
    path('uecontroller', handler),
]

然后将ueditor下的jsp下的config.json 文件复制粘贴到根目录下,如图:


最后修改uecontroller.py中uploadFile方法中的路径:


这时打开b页面为这个样式:


上传图片可到:


现在我们更改saveblog.html页面,使其可向b页面一样实现富文本:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <style>
        p{
            color: green;
        }
    </style>
    <script type="text/javascript" charset="utf-8" src="/static/ueditor/ueditor.config.js"></script>
    <script type="text/javascript" charset="utf-8" src="/static/ueditor/_examples/editor_api.js"></script>
</head>
<body>
<form method="post" action="saveblog">
    {% csrf_token %}
    <p>
        请输入标题: <input type="text" name="title">
    </p>
    <p>
        请输入内容: <textarea id="myEditor" name="content"></textarea>
    </p>
    <p>
        <input type="submit" name="" value="发布内容">
    </p>
    {{ error }}
</form>
<script type="text/javascript">
    var editor_a = UE.getEditor('myEditor',{serverUrl:'/blog/uecontroller'});
</script>
</body>
</html>

现在我们进入到saveblog页面即显示为:


之后我们创建一些博客数据,用来为后面的分页做准备。

要实现分页首先要导入一个模块:
from django.core.paginator import Paginator

然后在blog_user中的views里的welcome2重写函数:

from django.core.paginator import Paginator
from blog.models import Blog

#每次跳转welcome2页面都要查询某页的数据
def welcome2(request):
    user = request.session.get('user')
    blogSet=Blog.objects
    #查询哪些数据  __双下划线代表表连接
    blogSet = blogSet.values('id','title','create_date','blogUser__userName')
    #获取所有数据
    blogSet = blogSet.all().order_by('id')
    #设置获取第几页的数据
    pageNum = int (request.GET.get('pageNum',1))
    #分页器
    page=Paginator(blogSet,5)
    #判断是否为第一页
    isFirstPage=(pageNum==1)
    #判断是否为最后一页 num_pages一共多少页
    isLastPage=(pageNum==page.num_pages)

    return render(request,'user/welcome2.html',
                  {'user':user,
                   'blogSet':page.get_page(pageNum),#当前页的数据
                   'pageNum':pageNum,  #第几页数据
                   'ppageNum':pageNum-1,  #前一页
                   'npageNum':pageNum+1,  #后一页
                   'isFirstPage':isFirstPage,  #是否为第一页
                   'isLastPage':isLastPage,    #是否为最后一页
                   'totalPage':page.num_pages})   #总页数

上述函数为:首先创建了一个Blog模型blogSet,然后预查询了模型的id,标题,创建时间,并联合blogUser表查询了用户名(即为作者),又预查询了根据id排序的所有内容,设置pageNum为获取到的第几页(如果没有获取到pageNum,则为1),并将其转换为int类型,设置page为分页器,每5条博客为1页,若不足5条则也算作一页,接着设置了两个参数,判断当前是否为第一页或者是否为最后一页,并将这些参数传回到网页welcome2中。

现在在welcome2中显示分页结果并添加判断:

<p>
    {% if not isFirstPage %}
        <a href="welcome2?pageNum=1">首页</a>
        <a href="welcome2?pageNum={{ ppageNum }}">上一页</a>
    {% endif %}
    [{{ pageNum }}/{{ totalPage }}]
    {% if not isLastPage %}
        <a href="welcome2?pageNum={{ npageNum }}">下一页</a>
        <a href="welcome2?pageNum={{ totalPage }}">末页</a>
    {% endif %}
</p>

?代表传参

接着我们需要创建一个wenzhang.html页面用于存放博客内容,首先我们先来编写相关的路径及函数。

在blog中的urls中:path('wenzhang', views.wenzhang),

接着再views中:

def wenzhang(request):
    b_id = request.GET.get('id',1)
    blog = Blog.objects.get(pk=b_id)
    return render(request,'blog/wenzhang.html',
                    {'blog':blog})

接着我们在templates新建一个文件夹blog,里面创建一个wenzhang.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>标题{{ blog.title }}</h1>
    <h2>作者:{{ blog.blogUser.userName }}</h2>
    <p>发布时间:{{ blog.create_date|date:'Y-m-d h:i:s' }}</p>
    <div>
        {% autoescape off %}
        {{ blog.content }}
        {% endautoescape %}
    </div>

</body>
</html>

{% autoescape off %} {% endautoescape %}可以将html代码自动转译。

接着我们想在welcome2页面上显示每一页的数据:

{# 循环显示当前页的数据 #}
<ul>
    {% for blog in blogSet %}
    <li>
         <a href="/blog/wenzhang?id={{ blog.id }}">{{ blog.title }}</a>  
         作者:<span>{{ blog.blogUser__userName }}</span>  
         创建时间:<span>{{ blog.create_date|date:'Y-m-d h:i:s' }}</span>  
    </li>
    {% endfor %}
</ul>

blogSet为welcome2函数传进来的当前页面的数据;

| 为过滤器 上述使用的是将时间转换为年-月-日 时:分:秒的格式

打开welcome2页面:


随便点入一条博客显示:



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值