BBS项目之 点赞点踩 评论 编辑 文章详情展示 编辑文章
文章详情前端
1 {% extends 'base.html' %} 2 3 {% block title %} 4 {{ article.title }} 5 {% endblock %} 6 7 {% block css %} 8 <link rel="stylesheet" href="/static/css/mycss.css"> 9 {% endblock %} 10 11 12 {% block content %} 13 <div> 14 <h3 class="text-center">{{ article.title }}</h3> 15 <hr> 16 <div> 17 {{ article.content|safe }} 18 </div> 19 <!-- 20 点赞点踩 21 --> 22 <div class="clearfix"> 23 <div id="div_digg"> 24 <div class="diggit action"> 25 <span class="diggnum" id="digg_count">{{ article.up_num }}</span> 26 </div> 27 <div class="buryit action"> 28 <span class="burynum" id="bury_count">{{ article.down_num }}</span> 29 </div> 30 <div class="clear"></div> 31 <div class="diggword" id="digg_tips" style="color: red;"> 32 </div> 33 </div> 34 </div> 35 <hr> 36 <!-- 37 评论列表和评论输入框 38 #1楼 2018-03-22 13:33 Yif.Z 回复 39 峰哥,什么视频时候这个在线上班更新啊 40 --> 41 <div> 42 评论列表 43 <ul class="list-group"> 44 {% for comment in comment_list %} 45 <li class="list-group-item"> 46 <div> 47 <span>#{{ forloop.counter }}楼</span> 48 <span>{{ comment.create_time|date:'Y-m-d H-i-s' }}</span> 49 <span><a href="/{{ comment.user.username }}">{{ comment.user.username }}</a></span> 50 <span class="pull-right id_replay" username="{{ comment.user.username }} " 51 parent="{{ comment.pk }}"><a>回复</a></span> 52 </div> 53 <hr> 54 <div> 55 {% if comment.commit_id_id %} 56 <p>@{{ comment.commit_id.user.username }}</p> 57 <p>{{ comment.content }}</p> 58 {% else %} 59 {{ comment.content }} 60 {% endif %} 61 62 </div> 63 </li> 64 {% endfor %} 65 </ul> 66 67 </div> 68 {% if request.user.is_authenticated %} 69 <div> 70 <p class="glyphicon glyphicon-copyright-mark">发表评论</p> 71 <p><textarea name="" id="id_text" cols="180" rows="10"></textarea></p> 72 <p> 73 <button class="btn btn-success" id="id_comment">发表评论</button> 74 </p> 75 </div> 76 {% else %} 77 <div> 78 登录后才能发表评论,立即 <a href="/login/">登录</a> 或 <a href="/register/">注册</a>, 访问 网站首页 79 </div> 80 {% endif %} 81 82 83 </div> 84 {% endblock %} 85 86 {% block script %} 87 <script> 88 //把parent_id定义成全局变量 89 var parent_id = '' 90 $(".action").click(function () { 91 var is_up = $(this).hasClass('diggit') 92 var span = $(this).children('span') 93 $.ajax({ 94 url: '/upanddown/', 95 method: 'post', 96 data: { 97 article_id: '{{ article.id }}', 98 is_up: is_up, 99 csrfmiddlewaretoken: '{{ csrf_token }}' 100 }, 101 success: function (data) { 102 console.log(data) 103 $('#digg_tips').html(data.msg) 104 if (data.code == 100) { 105 //点赞或者点踩的数字加一 106 var num = Number(span.html()) + 1 107 span.html(num) 108 } 109 110 } 111 }) 112 113 }) 114 115 116 $('#id_comment').click(function () { 117 118 let content = $('#id_text').val() 119 if (parent_id) { 120 //这表示子评论 121 //取到字符串第一个\n的位置索引,是一个数字 122 let i = content.indexOf('\n') + 1 123 //从 \n+1的位置开始截取,截取到最后 124 content = content.slice(i) 125 } 126 $.ajax({ 127 url: '/comment/', 128 method: 'post', 129 data: { 130 article_id: '{{ article.id }}', 131 content: content, 132 parent: parent_id, 133 csrfmiddlewaretoken: '{{ csrf_token }}' 134 }, 135 success: function (data) { 136 console.log(data) 137 138 139 if (data.code == 100) { 140 141 let username = data.username 142 let res_content = data.content 143 let parent_name = data.parent_name 144 145 let ss = `` 146 if (parent_id) { 147 ss = `<li class="list-group-item"> 148 <div> 149 <span class="glyphicon glyphicon-comment">${username}</span> 150 </div> 151 <div> 152 <p>@${parent_name}</p> 153 ${res_content} 154 </div> 155 </li>` 156 } else { 157 ss = `<li class="list-group-item"> 158 <div> 159 <span class="glyphicon glyphicon-comment">${username}</span> 160 161 </div> 162 <div> 163 ${res_content} 164 </div> 165 </li>` 166 } 167 168 //清空输入框 169 $('#id_text').val('') 170 //把ss追加到评论列表的后面 171 $('.list-group').append(ss) 172 //把parent_id置空 173 parent_id = '' 174 } 175 176 177 } 178 }) 179 180 }) 181 182 $('.id_replay').click(function () { 183 let username = $(this).attr('username') 184 parent_id = $(this).attr('parent') 185 186 $('#id_text').val('@' + username + '\n').focus() 187 }) 188 </script> 189 {% endblock %}
点赞 点踩前端
<script> $(".action").click(function () { var is_up = $(this).hasClass('diggit') var span = $(this).children('span') $.ajax({ url: '/upanddown/', method: 'post', data: { article_id: '{{ article.id }}', is_up: is_up, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { console.log(data) $('#digg_tips').html(data.msg) if (data.code == 100) { //点赞或者点踩的数字加一 var num = Number(span.html()) + 1 span.html(num) } } }) })
点赞点踩后端
def upanddown(request): res = {'code': 100, 'msg': ''} if request.user.is_authenticated: # article表中数字加1,在点赞点踩表中记录一条 # 这个人对该文章只能点赞或者点踩一次 # 先查一下,如果有记录了,就不能再点了 article_id = request.POST.get('article_id') user_id = request.user.id is_up = request.POST.get('is_up') # is_up是一个字符串 print(type(is_up)) # if is_up=='true': # is_up=True # else: # is_up = False is_up = json.loads(is_up) print(type(is_up)) res_1 = models.UpAndDown.objects.filter(article_id=article_id, user_id=user_id).count() if res_1: res['code'] = 101 res['msg'] = '已经点过了' else: 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) res['msg'] = '点赞成功' else: models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1) res['msg'] = '点踩成功' else: res['code'] = 109 res['msg'] = '请先<a href="/login/">登录</a>' return JsonResponse(res)
评论前端
<script> //把parent_id定义成全局变量 var parent_id = '' $('#id_comment').click(function () { let content = $('#id_text').val() if (parent_id) { //这表示子评论 //取到字符串第一个\n的位置索引,是一个数字 let i = content.indexOf('\n') + 1 //从 \n+1的位置开始截取,截取到最后 content = content.slice(i) } $.ajax({ url: '/comment/', method: 'post', data: { article_id: '{{ article.id }}', content: content, parent: parent_id, csrfmiddlewaretoken: '{{ csrf_token }}' }, success: function (data) { console.log(data) if (data.code == 100) { let username = data.username let res_content = data.content let parent_name = data.parent_name let ss = `` if (parent_id) { ss = `<li class="list-group-item"> <div> <span class="glyphicon glyphicon-comment">${username}</span> </div> <div> <p>@${parent_name}</p> ${res_content} </div> </li>` } else { ss = `<li class="list-group-item"> <div> <span class="glyphicon glyphicon-comment">${username}</span> </div> <div> ${res_content} </div> </li>` } //清空输入框 $('#id_text').val('') //把ss追加到评论列表的后面 $('.list-group').append(ss) //把parent_id置空 parent_id = '' } } }) }) $('.id_replay').click(function () { let username = $(this).attr('username') parent_id = $(this).attr('parent') $('#id_text').val('@' + username + '\n').focus() }) </script>
评论后端
def comment(request): res = {'code': 100, 'msg': ''} if request.is_ajax(): article_id = request.POST.get('article_id') content = request.POST.get('content') parent = request.POST.get('parent') if request.user.is_authenticated: article = models.Commit.objects.create(user=request.user, article_id=article_id, content=content, commit_id_id=parent) models.Article.objects.filter(pk=article_id).update(commit_num=F('commit_num') + 1) res['msg'] = '评论成功' res['username'] = article.user.username res['content'] = article.content if parent: res['parent_name'] = article.commit_id.user.username # 发送邮件(同步操作) 课堂上使用的是这个 from django.core.mail import send_mail # send_mail('您的文章:%s被评论了'%'git从入门到放弃','%s评论了%s'%(request.user.username,'写的真好'),settings.EMAIL_HOST_USER, # ["1063926627@qq.com",'laichuangdelaoji@gmail.com'])
# 通过多线程,异步操作 from threading import Thread t=Thread(target=send_mail,args=('您的文章:%s被评论了'%'git从入门到放弃','%s评论了%s'%(request.user.username,'写的真好'),settings.EMAIL_HOST_USER,["1063926627@qq.com",'laichuangdelaoji@gmail.com'])) t.start() else: res['code'] = 109 res['msg'] = '请先登录' return JsonResponse(res)
发送邮件后端settings配置
EMAIL_HOST = 'smtp.qq.com' # 如果是 163 改成 smtp.163.com 以什么邮箱发送 EMAIL_PORT = 465 # 端口号 EMAIL_HOST_USER = '2209000808@qq.com' # 帐号 发送者邮箱账号 EMAIL_HOST_PASSWORD = 'wikeggxagkmmdjdj' # 密码 不是密码, 授权码 DEFAULT_FROM_EMAIL = EMAIL_HOST_USER EMAIL_USE_SSL = True #使用ssl,qq只支持这种
新增文章前端代码
{% extends 'backend/base.html' %} {% block content %} <div> <h4>新增文章</h4> <form action="" method="post"> {% csrf_token %} <div class="form-group"> <label> 标题</label> <input type="text" name="title" class="form-control"> </div> <div class="form-group"> <label for="">内容</label> <textarea name="content" id="editor_id" cols="80" rows="10" class="form-control"></textarea> </div> <div> 个人分类 {% for category in category_list %} <div class="radio"> <label for=""> <input type="radio" name="category" value="{{ category.id }}"> {{ category.name }} </label> </div> {% endfor %} </div> <div> 个人标签 {% for tag in tag_list %} <div class="checkbox"> <label for=""> <input type="checkbox" name="tag" value="{{ tag.id }}"> {{ tag.name }} </label> </div> {% endfor %} </div> <div class="text-center"> <input type="submit" class="btn btn-success" value="提交"> </div> </form> </div> {% endblock %} {% block script %} <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:'500px', resizeType:'/upload_img/', filePostName:'myfile', //额外带的参数 extraFileUploadParams:{ csrfmiddlewaretoken: '{{ csrf_token }}', } }) }) </script> {% endblock %}
富文本编辑器前端
<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:'500px', resizeType:'/upload_img/', filePostName:'myfile', //额外带的参数 extraFileUploadParams:{ csrfmiddlewaretoken: '{{ csrf_token }}', } }) })
新增文章 后端代码
@login_required(login_url='/login/') def new_article(request): if request.method == 'GET': category_list = models.Category.objects.filter(blog_id=request.user.blog) tag_list = models.Tag.objects.filter(blog=request.user.blog) print(category_list) return render(request, 'backend/add_article.html', locals()) else: title = request.POST.get('title') content = request.POST.get('content') category = request.POST.get('category') tags = request.POST.getlist('tag') # desc = content[0:90] # 会带着标签 soup = BeautifulSoup(content, 'html.parser') desc = soup.text[0:90] # 去掉所有标签后的文本 # 把script标签干掉 res_script = soup.find_all('script') for script in res_script: script.decompose() # 删除script标签 article = models.Article.objects.create(title=title, content=str(soup), desc=desc, blog=request.user.blog, category_id=category) # 存tag(自动生成第三张表) # article.tag.add(*tag) # 手动做 # for tag in tags: # models.TagToArticle.objects.create(article_id=article.pk,tag_id=tag) # 批量插入 ll = [] for tag in tags: ll.append(models.TagToArticle(article_id=article.pk, tag_id=tag)) models.TagToArticle.objects.bulk_create(ll) return redirect('/backend_index/')
上传图片后端代码
def upload_img(request): res = {'error':0} print(request.FILES) try: # 存图片 file = request.FILES.get('myfile') print(file,'上传的图片') path = os.path.join(settings.BASE_DIR, 'media', 'avatar', file.name) with open(path, 'wb') as f: for line in file: f.write(line) res['url'] = '/media/avatar/' + file.name except Exception as e: res['error'] = 1 res['message'] = str(e) return JsonResponse(res)
更新文章后端代码
from bs4 import BeautifulSoup @login_required(login_url='/login/') def update_article(request,id): if request.method == 'GET': article = models.Article.objects.get(id=id) category_list = models.Category.objects.filter(blog=request.user.blog) tag_list = models.Tag.objects.filter(blog=request.user.blog) # category_list = models.Category.objects.filter(blog=request.user.blog).annotate( # num=Count('article__id')).values_list( # 'name', 'num', 'id' # ) return render(request,'backend/update_article.html',locals()) else: title = request.POST.get('title') content = request.POST.get('content') category = request.POST.get('category') tags = request.POST.getlist('tag') #desc = content[0:90] #会带着标签 soup = BeautifulSoup(content,'html.parser') desc = soup.text[0:90] #去掉所有标签后的文本 #把script标签干掉 res_script = soup.find_all('script') for script in res_script: script.decompose() #删除script标签 article = models.Article.objects.filter(pk=id) article.update(title=title,content=str(soup),desc=desc,category_id=category) ll = [] for tag in tags: ll.append(models.TagToArticle(article_id=article.first().pk, tag_id=tag)) models.TagToArticle.objects.bulk_create(ll) return redirect('/backend_index/')
更新文章前端代码
{% extends 'backend/base.html' %} {% block content %} <div> <h4>修改文章</h4> <form action="/update_article/{{ article.pk }}/" method="post"> {% csrf_token %} <div class="form-group"> <label for="">标题</label> <input type="text" name="title" class="form-control" value="{{ article.title }}"> </div> <div class="form-group"> <label for="">内容</label> <textarea name="content" id="editor_id" cols="80" rows="10" class="form-control"> {{ article.content }} </textarea> </div> <div> 个人分类 {% for category in category_list %} <div class="radio"> <label> <input type="radio" name="category" value="{{ category.id }}"> {{ category.name }} </label> </div> {% endfor %} </div> <div> 个人标签 {% for tag in tag_list %} <div class="checkbox"> <label> <input type="checkbox" name="tag" value="{{ tag.id }}"> {{ tag.name }} </label> </div> {% endfor %} </div> <div class="text-center"> <input type="submit" class="btn btn-success" value="提交"> </div> </form> </div> {% endblock %} {% block script %} <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: '500px', resizeType: 1, uploadJson:'/upload_img/', filePostName:'myfile', //额外带的参数 extraFileUploadParams : { csrfmiddlewaretoken: '{{ csrf_token }}', } }); }); </script> {% endblock %}