添加(富文本编辑器)
Posted sima-3
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了添加(富文本编辑器)相关的知识,希望对你有一定的参考价值。
一.文章详情
路由url.py:
url(r‘^(?P<username>\w+)/article/(?P<pk>\d+)$‘, views.article_detail),
点击个人站点文章title即可关联到文章详情路由找到其视图函数
views.py:
def article_detail(request,username,pk): user = models.UserInfo.objects.filter(username=username).first() if not user: return render(request, ‘error.html‘) blog = user.blog category_ret=models.Category.objects.all().filter(blog=blog).annotate(cou=Count(‘article__nid‘)).values_list(‘title‘,‘cou‘,‘nid‘) tag_ret=models.Tag.objects.all().filter(blog=blog).annotate(cou=Count(‘article__nid‘)).values_list(‘title‘,‘cou‘,‘nid‘) year_ret=models.Article.objects.all().annotate(month=TruncMonth(‘create_time‘)).values(‘month‘).annotate(c=Count(‘nid‘)).values_list(‘month‘,‘c‘) article=models.Article.objects.filter(nid=pk).first() # commit_list=article.commit_set.all() 前台模板渲染也可获取评论列表 return render(request,‘article_detail.html‘,locals())
ps: 通过有名分组拿到用户名和文章id,找到该文章对象渲染到article_detail.html (用到了母版base.html)
base.html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> blog.title 的个人站点</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <link rel="stylesheet" href="/static/css/ blog.theme "> <script src="/static/jquery-3.3.1.js"></script> % block mycss % % endblock % </head> <body> <div class="head"> blog.site_name </div> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="panel panel-danger"> <div class="panel-heading">我的标签</div> <div class="panel-body"> % for tag in tag_ret % <p><a href="/ user.username /tag/ tag.2 "> tag.0 ( tag.1 )</a></p> % endfor % </div> </div> <div class="panel panel-success"> <div class="panel-heading"> <h3 class="panel-title">随笔分类</h3> </div> <div class="panel-body"> % for category in category_ret % <p> <a href="/ user.username /category/ category.2 "> category.0 ( category.1 )</a> </p> % endfor % </div> </div> <div class="panel panel-success"> <div class="panel-heading"> <h3 class="panel-title">随笔档案</h3> </div> <div class="panel-body"> % for year in year_ret % <p> <a href="/ user.username /archive/ year.0|date:"Y-m" "> year.0|date:"Y年m月" ( year.1 )</a> </p> % endfor % </div> </div> </div> <div class="col-md-9"> % block content % % endblock % </div> </div> </div> </body> </html>
article_detail.html:
% extends ‘base.html‘ % % block mycss % <link rel="stylesheet" href="/static/css/commoncss.css"> % endblock % % block content % <div> <h4> article.title </h4> <div> article.content|safe </div> <div class="clearfix"> <div id="div_digg"> <div class="diggit upanddown"> <span class="diggnum" id="digg_count"> article.up_num </span> </div> <div class="buryit upanddown"> <span class="burynum" id="bury_count"> article.down_num </span> </div> <div class="clear"></div> <div class="diggword" id="digg_tips" style="color: red;"></div> </div> </div> <div> #评论相关# <div> #评论列表# <p>评论列表</p> <ul class="list-group commit_content"> % for commit in article.commit_set.all % <li class="list-group-item"> <p> <span># forloop.counter 楼</span> <span> commit.create_time|date:"Y-m-d H:i" </span> <span> commit.user.username </span> <span class="pull-right reply" username=" commit.user.username " commit_id=" commit.pk "><a>回复</a></span> </p> % if commit.parent % <p class="well">@ commit.parent.user.username ---- commit.parent.content </p> % endif % commit.content </li> % endfor % </ul> </div> <div> #发表评论# <p>发表评论</p> <p> 昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value=" request.user.username "> </p> <p>评论内容</p> <textarea name="" id="id_textarea" cols="80" rows="10"> </textarea> <p> <button class="btn btn-success" id="btn_submit">提交</button> </p> </div> </div> </div> <script> var parent_id = ‘‘ //评论相关 $("#btn_submit").click(function () var content = $("#id_textarea").val() if (parent_id) //有值,截取前面的@姓名 //indexof 截取 \n的索引位置 var index = content.indexOf(‘\n‘) + 1 content = content.slice(index) //谁对那篇文章评论了什么内容 $.ajax( url: ‘/commit/‘, type: ‘post‘, data: article_id: ‘article.pk‘, content: content, csrfmiddlewaretoken: ‘ csrf_token ‘, parent_id: parent_id , success: function (data) console.log(data) //清除输入框的数据 $("#id_textarea").val("") if (data.code == 100) var username = data.username var reply_content = data.reply_content //往后追加内容 if (parent_id) var parent_name = data.parent_name var s = ` <li class="list-group-item"> <p> <span>$username</span> </p> <p class="well">@$parent_name</p> $reply_content </li> ` else //追加根评论的内容 //es6的字符串替换 var s = ` <li class="list-group-item"> <p> <span>$username</span> </p> $reply_content </li> ` $(".commit_content").append(s) ) ) //回复相关 $(".reply").click(function () var username = ‘@‘ + $(this).attr(‘username‘) + ‘\n‘ parent_id = $(this).attr(‘commit_id‘) //光标聚焦到该控件上 $("#id_textarea").focus() $("#id_textarea").val(username) ) //点赞点踩相关 $(".upanddown").click(function () //当前点击控件有没有diggit 这个类 var is_up = $(this).hasClass(‘diggit‘) //拿到当前点击控件子控件的span标签对象 var cu_span = $(this).children(‘span‘) //alert(is_up) //谁对哪篇文章点赞或点踩 $.ajax( url: ‘/diggit/‘, type: ‘post‘, data: article_id: ‘article.pk‘, is_up: is_up, csrfmiddlewaretoken: ‘ csrf_token ‘, success: function (data) console.log(data) $("#digg_tips").html(data.msg) if (data.code == 100) #cu_span.text(cu_span.text()+1)# //在当前点击的div下的span标签上数字加以 cu_span.text(Number(cu_span.text()) + 1) ) ) </script> % endblock %
文章详情展示了以下内容: 文章title, 文章content (传html文件,用safe转义),点赞点踩,评论列表,评论内容:
a.点赞点踩:
<div class="clearfix"> <div id="div_digg"> <div class="diggit upanddown"> <span class="diggnum" id="digg_count"> article.up_num </span> </div> <div class="buryit upanddown"> <span class="burynum" id="bury_count"> article.down_num </span> </div> <div class="clear"></div> <div class="diggword" id="digg_tips" style="color: red;"></div> </div> </div>
js:
//点赞点踩相关 $(".upanddown").click(function () //当前点击控件有没有diggit 这个类 var is_up = $(this).hasClass(‘diggit‘) //拿到当前点击控件子控件的span标签对象 var cu_span = $(this).children(‘span‘) //alert(is_up) //谁对哪篇文章点赞或点踩 $.ajax( url: ‘/diggit/‘, type: ‘post‘, data: article_id: ‘article.pk‘, is_up: is_up, csrfmiddlewaretoken: ‘ csrf_token ‘, success: function (data) console.log(data) $("#digg_tips").html(data.msg) if (data.code == 100) #cu_span.text(cu_span.text()+1)# //在当前点击的div下的span标签上数字加以 cu_span.text(Number(cu_span.text()) + 1) )
点赞点踩视图函数: 开启事务,将点赞点踩表创建记录的同时,把文章表的点赞或点踩数也加一
import json from django.db.models import F def diggit(request): response=‘code‘:100,‘msg‘:None #当前登陆用户id if request.user.is_authenticated(): user_id=request.user.nid is_up=request.POST.get(‘is_up‘) print(type(is_up)) print(is_up) is_up=json.loads(is_up) print(type(is_up)) print(is_up) article_id=request.POST.get(‘article_id‘) up_ret=models.UpAndDown.objects.filter(user_id=user_id,article_id=article_id).first() if up_ret: response[‘code‘] = 102 response[‘msg‘] = ‘您已经点过了‘ else: #事务性的操作 from django.db import transaction #开启事务 with transaction.atomic(): models.UpAndDown.objects.create(article_id=article_id,user_id=user_id,is_up=is_up) if is_up: #文章表点赞字段加一 models.Article.objects.filter(pk=article_id).update(up_num=F(‘up_num‘)+1) response[‘msg‘] = ‘点赞成功‘ else: models.Article.objects.filter(pk=article_id).update(down_num=F(‘down_num‘)+1) response[‘msg‘] = ‘点踩成功‘ else: response[‘code‘]=101 response[‘msg‘]=‘请先登陆‘ return JsonResponse(response,safe=False)
b.评论列表:
<div> #评论相关# <div> #评论列表# <p>评论列表</p> <ul class="list-group commit_content"> % for commit in article.commit_set.all % <li class="list-group-item"> <p> <span># forloop.counter 楼</span> <span> commit.create_time|date:"Y-m-d H:i" </span> <span> commit.user.username </span> <span class="pull-right reply" username=" commit.user.username " commit_id=" commit.pk "><a>回复</a></span> </p> % if commit.parent % <p class="well">@ commit.parent.user.username ---- commit.parent.content </p> % endif % commit.content </li> % endfor % </ul> </div>
c.发表评论:
<div> #发表评论# <p>发表评论</p> <p> 昵称:<input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50" value=" request.user.username "> </p> <p>评论内容</p> <textarea name="" id="id_textarea" cols="80" rows="10"> </textarea> <p> <button class="btn btn-success" id="btn_submit">提交</button> </p> </div>
js:
var parent_id = ‘‘ //评论相关 $("#btn_submit").click(function () var content = $("#id_textarea").val() if (parent_id) //有值,截取前面的@姓名 //indexof 截取 \n的索引位置 var index = content.indexOf(‘\n‘) + 1 content = content.slice(index) //谁对那篇文章评论了什么内容 $.ajax( url: ‘/commit/‘, type: ‘post‘, data: article_id: ‘article.pk‘, content: content, csrfmiddlewaretoken: ‘ csrf_token ‘, parent_id: parent_id , success: function (data) console.log(data) //清除输入框的数据 $("#id_textarea").val("") if (data.code == 100) var username = data.username var reply_content = data.reply_content //往后追加内容 if (parent_id) var parent_name = data.parent_name var s = ` <li class="list-group-item"> <p> <span>$username</span> </p> <p class="well">@$parent_name</p> $reply_content </li> ` else //追加根评论的内容 //es6的字符串替换 var s = ` <li class="list-group-item"> <p> <span>$username</span> </p> $reply_content </li> ` $(".commit_content").append(s) ) ) //回复相关 $(".reply").click(function () var username = ‘@‘ + $(this).attr(‘username‘) + ‘\n‘ parent_id = $(this).attr(‘commit_id‘) //光标聚焦到该控件上 $("#id_textarea").focus() $("#id_textarea").val(username) )
评论视图函数:开启事务,在评论表添加记录的同时,也在文章表添加评论数
def commit(request): response = ‘code‘: 100, ‘msg‘: None # 当前登陆用户id if request.user.is_authenticated(): user_id = request.user.nid article_id = request.POST.get(‘article_id‘) content=request.POST.get(‘content‘) parent_id=request.POST.get(‘parent_id‘) # 事务性的操作 from django.db import transaction # 开启事务 with transaction.atomic(): ret=models.Commit.objects.create(article_id=article_id,content=content,user_id=user_id,parent_id=parent_id) models.Article.objects.filter(pk=article_id).update(comment_num=F(‘comment_num‘) + 1) response[‘username‘]=ret.user.username response[‘reply_content‘]=ret.content if parent_id: response[‘parent_name‘] = ret.parent.user.username response[‘msg‘] = ‘评论成功‘ else: response[‘code‘] = 101 response[‘msg‘] = ‘请先登陆‘ return JsonResponse(response, safe=False)
二.后台展示,添加文章
路由url.py:
# 后台管理首页 url(r‘^backend/‘, views.home_backend),
视图函数:
from django.contrib.auth.decorators import login_required @login_required(login_url=‘/login/‘) def home_backend(request): #查询该人的所有文章 ariticle_list=models.Article.objects.filter(blog=request.user.blog) return render(request,‘backend/home_backend.html‘,locals())
前端渲染母版backend_base.html:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>后台管理</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap-3.3.7-dist/js/bootstrap.js"></script> </head> <body> <div class="head" style="height: 60px;background-color: #2b669a"> <p>后台管理</p> </div> <div class="container-fluid"> <div class="row"> <div class="col-md-3"> <div class="panel-group" id="accordion" role="tablist" aria-multiselectable="true"> <div class="panel panel-default"> <div class="panel-heading" role="tab" id="headingOne"> <h4 class="panel-title"> <a role="button" data-toggle="collapse" data-parent="#accordion" href="#collapseOne" aria-expanded="true" aria-controls="collapseOne"> 文章管理 </a> </h4> </div> <div id="collapseOne" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <a href="/add_article/">添加文章</a>
跳到添加文章路由
</div> </div> <div id="xxx" class="panel-collapse collapse in" role="tabpanel" aria-labelledby="headingOne"> <div class="panel-body"> <a href="">添加随笔</a> </div> </div> </div> </div> </div> <div class="col-md-9"> <div> <!-- Nav tabs --> <ul class="nav nav-tabs" role="tablist"> <li role="presentation" class="active"><a href="#home" aria-controls="home" role="tab" data-toggle="tab">文章</a></li> <li role="presentation"><a href="#profile" aria-controls="profile" role="tab" data-toggle="tab">随笔</a> </li> <li role="presentation"><a href="#messages" aria-controls="messages" role="tab" data-toggle="tab">交友</a> </li> <li role="presentation"><a href="#settings" aria-controls="settings" role="tab" data-toggle="tab">相册</a> </li> </ul> <!-- Tab panes --> <div class="tab-content"> <div role="tabpanel" class="tab-pane active" id="home"> % block content % % endblock % </div> <div role="tabpanel" class="tab-pane" id="profile">随笔</div> <div role="tabpanel" class="tab-pane" id="messages">交友</div> <div role="tabpanel" class="tab-pane" id="settings">相册</div> </div> </div> </div> </div> </div> </body> </html>
后台管理前端home_backend.html:
% extends ‘backend/backend_base.html‘ % % block content % <table class="table table-striped"> <thead> <tr> <th>标题</th> <th>评论数</th> <th>点赞数</th> <th>操作</th> <th>操作</th> </tr> </thead> <tbody> % for ariticle in ariticle_list % <tr> <td><a href="/ request.user.username /article/ ariticle.pk "> ariticle.title </a></td>
跳到文章详情路由 <td> ariticle.commit_num </td> <td> ariticle.up_num </td> <td><a href="">删除</a></td> <td><a href="">编辑</a></td> </tr> % endfor % </tbody> </table> % endblock %
添加文章路由:
# 添加文章 url(r‘^add_article/‘, views.add_article),
添加文章视图函数:(用bs4来解析html文档,删除script标签内容来防止xss
@login_required(login_url=‘/login/‘) def add_article(request): if request.method==‘GET‘: return render(request,‘backend/add_article.html‘) else: title=request.POST.get(‘title‘) text_content=request.POST.get(‘text_content‘) #通过bs4 处理xss攻击,html文档解析库 #pip3 install beautifulsoup4 from bs4 import BeautifulSoup soup=BeautifulSoup(text_content,‘html.parser‘) #查找所有的标签 tags=soup.find_all() for tag in tags: if tag.name==‘script‘: #从文档中删除该标签 tag.decompose() #soup.text 文档的内容,不包含标签 desc=soup.text[0:150] models.Article.objects.create(title=title,desc=desc,content=str(soup),blog=request.user.blog) return redirect(‘/backend/‘)
添加文章add_article.html(借助富文本编辑器):
% extends ‘backend/backend_base.html‘ % % block content % <div> <p>添加文章</p> <form action="/add_article/" method="post"> % csrf_token % <div class="form-group"> <label for="id_name">文章标题</label> <input type="text" name="title" id="id_title" class="form-control"> </div> <p>内容(KindEditor编辑器,不支持拖放/粘贴上传图片) </p> <textarea name="text_content" id="editor_id" cols="30" rows="10"></textarea> <p> <button class="btn btn-success">提交</button> </p> </form> </div> <script charset="utf-8" src="/static/kindeditor/kindeditor-all.js"></script> <script> KindEditor.ready(function (K) window.editor = K.create(‘#editor_id‘, width: ‘100%‘, height: ‘400px‘, resizeType: 0, #items: [# # ‘source‘, ‘|‘, ‘undo‘, ‘redo‘, ‘|‘, ‘preview‘, ‘print‘, ‘template‘, ‘code‘, ‘cut‘, ‘copy‘, ‘paste‘,# # ‘plainpaste‘, ‘wordpaste‘, ‘|‘# #]# uploadJson: ‘/uploadimg/‘, extraFileUploadParams: csrfmiddlewaretoken: ‘ csrf_token ‘, ); ); </script> % endblock %
在富文本编辑器中上传图片,图片地址放在media/file下即可:
@login_required(login_url=‘/login/‘) def uploadimg(request): response= "error" : 0, "url" : None fil=request.FILES.get(‘imgFile‘) with open(‘media/file/‘+fil.name,‘wb‘) as f: for line in fil: f.write(line) response[‘url‘]=‘/media/file/‘+fil.name return JsonResponse(response)
以上是关于添加(富文本编辑器)的主要内容,如果未能解决你的问题,请参考以下文章