django框架前后端混合项目之子评论、后台管理页面富文本编辑器、修改头像、修改密码等相关内容-81

1 根评论功能

#1 js中 es6语法,反引号的用法
var content='sb'
`egon is ${content}`

前端

评论列表

<div>
  评论列表
   <ul class="list-group">
      {% for comment in comment_list %}
           <li class="list-group-item">
               <div>
                   <span>#{{ forloop.counter }}楼</span>
                   <span>{{ comment.create_time|date:'Y-m-d H-i-s' }}</span>
                   <span><a href="/{{ comment.user.username }}">{{ comment.user.username }}</a></span>
                   <span class="pull-right id_replay" username="{{ comment.user.username }} "
                         parent="{{ comment.pk }}"><a>回复</a></span>
               </div>
               <hr>
               <div>
                  {% if comment.commit_id_id %}
                       <p>@{{ comment.commit_id.user.username }}</p>
                       <p>{{ comment.content }}</p>
                  {% else %}
                      {{ comment.content }}
                  {% endif %}

               </div>
           </li>
      {% endfor %}
   </ul>

</div>

评论框

{% if request.user.is_authenticated %}
   <div>
       <p class="glyphicon glyphicon-copyright-mark">发表评论</p>
       <p><textarea name="" id="id_text" cols="180" rows="10"></textarea></p>
       <p>
           <button class="btn btn-success" id="id_comment">发表评论</button>
       </p>
   </div>
{% else %}
   <div>
      登录后才能发表评论,立即 <a href="/login/">登录</a> 或 <a href="/register/">注册</a>, 访问 网站首页
   </div>
{% endif %}

js代码

$('#id_comment').click(function () {
   let content = $('#id_text').val()
   $.ajax({
       url: '/comment/',
       method: 'post',
       data: {
           article_id: '{{ article.id }}',
           content: content,
           parent: parent_id,
           csrfmiddlewaretoken: '{{ csrf_token }}'
      },
       success: function (data) {
           if (data.code == 100) {
               let username = data.username
               let res_content = data.content
               let ss = ``
               ss = `<li class="list-group-item">
                       <div>
                           <span class="glyphicon glyphicon-comment">${username</span>
                       </div>
                       <div>
                       <p>@${parent_name}</p>
                           ${res_content}
                       </div>
                   </li>`
             
               //清空输入框
               $('#id_text').val('')
               //把ss追加到评论列表的后面
               $('.list-group').append(ss)
          }


      }
  })

})

后端

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

       else:
           res['code'] = 109
           res['msg'] = '请先登录'

   return JsonResponse(res)

 

2 子评论功能

后端同上

前端js


$('#id_comment').click(function () {

   let content = $('#id_text').val()
   if (parent_id) {
       //这表示子评论
       //取到字符串第一个 的位置索引,是一个数字
       let i = content.indexOf(' ') + 1
       //从 +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 + ' ').focus()
})

 

 

3 后台管理页面搭建

backend/base.html

<!DOCTYPE html>
<html lang="en">
<head>
   <meta charset="UTF-8">
   <title>后台管理</title>
   <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
   <link rel="stylesheet" href="/static/font-awesome-4.7.0/css/font-awesome.css">
   <script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
   <script src="/static/bootstrap/js/bootstrap.min.js"></script>
   <style>

   </style>
</head>
<body>
<div>
   <div class="header">
       <nav class="navbar navbar-default navbar-inverse">
           <div class="container-fluid">
               <div class="navbar-header">
                   <a class="navbar-brand" href="#">后台管理</a>
               </div>

               <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
                   <ul class="nav navbar-nav">
                       <li class="active"><a href="/index/">首页 <span class="sr-only">(current)</span></a></li>

                   </ul>
               </div><!-- /.navbar-collapse -->
           </div><!-- /.container-fluid -->
       </nav>
   </div>
   <div class="container-fluid">

       <div class="row">
           <div class="left_content 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">
                               <ul class="nav">
                                   <li><a href="/new_article/">新增文章</a></li>
                                   <li><a href="">新增随笔</a></li>
                               </ul>

                           </div>
                       </div>
                   </div>
                   <div class="panel panel-default">
                       <div class="panel-heading" role="tab" id="headingTwo">
                           <h4 class="panel-title">
                               <a class="collapsed" role="button" data-toggle="collapse" data-parent="#accordion"
                                  href="#collapseTwo" aria-expanded="false" aria-controls="collapseTwo">
                                   分类
                               </a>
                           </h4>
                       </div>
                       <div id="collapseTwo" class="panel-collapse collapse" role="tabpanel"
                            aria-labelledby="headingTwo">
                           <div class="panel-body">
                           </div>
                       </div>
                   </div>
               </div>
           </div>
           <div class="right_content 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>


</div>

</body>
{% block script %}

{% endblock %}
</html>

backend/backend_index.html

{% extends 'backend/base.html' %}
{% block content %}
   <table class="table table-hover table-striped">
   <thead>
   <tr>
       <th>标题</th>
       <th>评论数</th>
       <th>点赞数</th>
       <th>操作</th>
       <th>操作</th>
   </tr>
   </thead>
   <tbody >
      {% for article in article_list %}
           <tr>
           <td><a href="/{{ article.blog.userinfo.username }}/article/{{ article.pk }}.html">{{ article.title }}</a></td>
           <td>{{ article.commit_num }}</td>
           <td>{{ article.up_num }}</td>
           <td><a href="">编辑</a></td>
           <td><a href="">删除</a></td>
           </tr>
      {% endfor %}

   </tbody>
   </table>
{% endblock %}

后台

@login_required(login_url='/login/')
def backend_index(request):
    article_list = models.Article.objects.filter(blog=request.user.blog)
    return render(request, 'backend/backend_index.html', locals())

4 富文本编辑器使用

# 1 下载kindeditor:http://kindeditor.net/down.php
# 2 解压缩,把整个文件加放入static目录下
# 3 再add_article.html中
    <div class="form-group">
    <label for="">内容</label>
    <textarea name="content" id="editor_id" cols="80" rows="10" class="form-control">	 </textarea>
    </div>
# 3 js代码
    <script charset="utf-8" src="/static/kindeditor/kindeditor-all.js"></script>
    <script>
        KindEditor.ready(function (K) {
            window.editor = K.create('#editor_id', {
                 '100%',
                height: '500px',
                resizeType: 1,


            });
        });

5 新增文章,处理xss攻击

# pip3 install beautifulsoup4
from bs4 import BeautifulSoup

@login_required(login_url='/login/')
def new_article(request):
    if request.method == 'GET':
        category_list = models.Category.objects.filter(blog=request.user.blog)
        tag_list = models.Tag.objects.filter(blog=request.user.blog)
        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/')

 

6 富文本编辑器上传图片

js

 

 KindEditor.ready(function (K) {
            window.editor = K.create('#editor_id', {
                 '100%',
                height: '500px',
                resizeType: 1,
                uploadJson:'/upload_img/',
                filePostName:'myfile',
                //额外带的参数
                extraFileUploadParams : {
                      csrfmiddlewaretoken: '{{ csrf_token }}',

                }


            });
        });

后端

def upload_img(request):
    res={'error':0}
    print(request.FILES)
    try:
        # 存图片
        file=request.FILES.get('myfile')
        path=os.path.join(settings.BASE_DIR,'media','img',file.name)
        with open(path,'wb') as f:
            for line in file:
                f.write(line)
        res['url']='/media/img/'+file.name
    except Exception as e:
        res['error']=1
        res['message']=str(e)
    return JsonResponse(res)

7 修改头像

后台

@login_required(login_url='/login/')
def update_head(request):
    if request.method=='GET':
        return render(request,'backend/update_head.html')
    else:
        head=request.FILES.get('myfile')
        # 方式一
        request.user.avatar=head
        request.user.save()
        return redirect('/')
        # 方式二(不可以,它不能自动添加上avatar/前缀)
        # models.UserInfo.objects.filter(pk=request.user.id).update(avatar=head)
        # return redirect('/')

前端

{% extends 'backend/base.html' %}

{% block head %}
    <form action="" method="post" enctype="multipart/form-data">
    {% csrf_token %}
        <div class="form-group">
            <label for="">原头像</label>
            <img src="/media/{{ request.user.avatar }}" height="80" width="80">
        </div>
        <div class="form-group">
            <label for="id_myfile">头像
                <img src="/static/img/default.png" alt="" id="id_img" height="80" width="80"
                     style="margin-left: 10px">
            </label>

            <input type="file" accept="image/*" name="myfile" id="id_myfile" style="display: none">
        </div>

        <div class="text-center">
            <input type="submit" value="修改" id="id_submit" class="btn btn-danger "><span
                class="error text-danger" style="margin-left: 10px"></span>
        </div>
    </form>
{% endblock %}


{% block script %}

    <script>
        $("#id_myfile").change(function () {
            //借助于文件阅读器
            let filereader = new FileReader()
            //把图片读到filereader对象中
            //$('#id_myfile')[0].files[0]
            filereader.readAsDataURL($('#id_myfile')[0].files[0])
            //$('#id_img').attr('src','https://account.cnblogs.com/images/registersideimg.png')
            //$('#id_img').attr('src',filereader.result) //这样不行,文件没读完
            filereader.onload = function () {
                //文件完全读到文件阅读器以后,再执行
                $('#id_img').attr('src', filereader.result)
            }
        })
    </script>
{% endblock %}

8 修改密码

前端

$('#btn_pwd_submit').click(function () {
    $(this).prop('disabled', true)
    $.ajax({
        url: '/update_pwd/',
        method: 'post',
        data: {
            pwd: $('#id_new_pwd').val(),
            csrfmiddlewaretoken: '{{ csrf_token }}',
        },
        success: function (data) {

            $('#btn_pwd_submit').prop('disabled', false)
            $('#id_alert').removeClass('hidden').children('strong').html(data.msg)
            setTimeout(function () {
                $('#id_alert').addClass('hidden')
            },3000)
            if (data.code == 100) {
                //模态框销毁
                $('#myModal').modal('hide')
            }

        }
    })


})

后端

def update_pwd(request):
    res = {'code': 100, 'msg': '密码修改成功'}
    try:
        pwd = request.POST.get('pwd')
        print(pwd)
        request.user.set_password(pwd)
        request.user.save()
    except Exception:
        res['code'] = 101
        res['msg'] = '密码修改失败'
    return JsonResponse(res)

9 删除文件,修改文章

自己实现

 

10 邮件通知(django中发送邮件)

# 评论成功发送邮件
# django现成的函数,可以直接发送邮件

#1 setting中配置
EMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.com   以什么邮箱发送
EMAIL_PORT = 465    # 端口号
EMAIL_HOST_USER = '306334678@qq.com'  # 帐号 发送者邮箱账号
EMAIL_HOST_PASSWORD = ''  # 密码 不是密码, 授权码
DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
EMAIL_USE_SSL = True   #使用ssl,qq只支持这种

# 2 视图函数中使用
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'])

 

 

原文地址:https://www.cnblogs.com/usherwang/p/14235010.html