• 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'])
    
    

     

     

  • 相关阅读:
    mysql 高效分页控件及c#调用实例
    sql server高效分页控件及c#调用实例
    Log4net从下载到使用例子
    Nlog从下载到使用例子
    使用httpClient调用接口,参数用map封装或者使用JSON参数,并转换返回结果
    Pool thread stack traces: Thread[C3P0PooledConnectionPoolManager[identityToken->原因解决办法
    使用spring的aop监听所有controller或者action日志
    ActiveMQ监听消息并进行转发,监听不同的mq服务器和不同的队列
    zookeeper集群查看状态时报错Error contacting service. It is probably not running的一些坑以及解决办法
    AopProxyUtils.getSingletonTarget(Ljava/lang/Object;)Ljava/lang/Object;大坑
  • 原文地址:https://www.cnblogs.com/usherwang/p/14235010.html
Copyright © 2020-2023  润新知