• 7 功能5:文章详情页、评论、评论树


    1、文章详情页之评论如何实现?

     2、根评论

    1、根评论样式

      

            input.author {
                background-image: url('/static/img/icon_form.gif');
                background-repeat: no-repeat;
                border: 1px solid #ccc;
                padding: 4px 4px 4px 30px;
                 230px;
            }
                  <div class="comments">
                        <p>发表评论</p>
                        <p>昵称</p><input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                                        value={{ request.user.username }}>
                        <p>评论内容</p>
                        <textarea name="" id="" cols="60" rows="10"></textarea>
                        <p>
                            <button class="btn btn-default comment_btn">提交评论</button>
                        </p>
                    </div>

     

    2、提交根评论

     

     

     

     3、显示根评论

                        <p>评论列表</p>
                        <ul class="list-group comment_list">
                            {% for comment in comment_list %}
                                <li class="list-group-item">
                                    <div class="comment_head">
                                        <a href=""># {{ forloop.counter }}楼</a>&nbsp;&nbsp;
                                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                                        <a href="">{{ comment.user.username }}</a>
                                        <a href="" class="pull-right">回复</a>
                                    </div>
    
                                    <div class="comment_content">
                                        <p>{{ comment.content }}</p>
                                    </div>
                                </li>
                            {% endfor %}
    
                        </ul>
    评论列表

     4、ajax显示评论:es6 模板字符串

    • ES6引入了模板字符串解决 字符串拼接问题+++

      深入了解es6 模板字符串 https://www.cnblogs.com/bfc0517/p/6700849.html

    def comment(request):
        """评论视图"""
        article_id = request.POST.get("article_id")
        content = request.POST.get("content")
        parent_id = request.POST.get("parent_id")
        user_id = request.user.pk
    
        # 创建一条评论
        comment_obj = models.Comment.objects.create(user_id=user_id,article_id=article_id,
                                                    content=content,parent_comment_id=parent_id)
    
        response = {}
        response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X")
        response["username"] = request.user.username
        response["content"] = content
    
    
        return JsonResponse(response)
    根评论视图

       //评论请求
        $('.comment_btn').click(function () {
            var parent_id = ""
            var content = $("#comment_content").val()
            $.ajax({
                url: '/comment/',
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                    "article_id":{{ article_obj.pk }},
                    "content": content,
                    "parent_id": parent_id
    
                },
                success: function (data) {
                    console.log(data);
    
                    // dom操作  es6  标签字符串
                    var create_time = data.create_time
                    var username = data.username
                    var content = data.content
    
                    var s = `
                            <li class="list-group-item">
                                <div class="comment_head">
                                    <span>${create_time}</span>&nbsp;&nbsp;
                                    <a href="">${username}</a>
                                    <a href="" class="pull-right">回复</a>
                                </div>
    
                                <div class="comment_content">
                                    <p>${content}</p>
                                </div>
                            </li>`;
    
    
                    $("ul").append(s)
    
                    //清空评论框
                    $("#comment_content").val("")
                }
            })
        })
    View Code

    3、子评论

    1、回复按钮

    2、提交子评论

    如果是子评论,就从
    开始取字符串

     

    # indexOf()
    定义和用法
    indexOf() 方法可返回某个指定的字符串值在字符串中首次出现的位置。
    语法
    stringObject.indexOf(searchvalue,fromindex)
    
    # slice()
    定义和用法
    slice() 方法可从已有的数组中返回选定的元素。
    语法
    arrayObject.slice(start,end)

     

    3、render显示子评论

     4、ajax显示子评论

    if 父评论

      显示s  

    如果子评论

      显示 新的样式

    4、评论树

    1、评论树简介

      1、方式1:递归完成
         2、方式2:评论树展示数据

    2、评论树的请求数据

        # 评论
        re_path('^comment/$', views.comment, name='comment'),
        # 评论树
        re_path('^get_comment_tree/$', views.get_comment_tree, name='get_comment_tree'),

    def get_comment_tree(request):
        """评论树"""
        article_id = request.GET.get("article_id")
        ret = list(models.Comment.objects.filter(article_id=article_id).values("pk", "content","parent_comment_id"))
    
        return JsonResponse(ret,safe=False)

         

     3、展开评论树1:根评论

     4、展开评论树2:子评论

     5、评论树思考

        //评论树
        $(".tree_btn").click(function () {
            $.ajax({
                url: "/get_comment_tree/",
                type: "get",
                data: {
                    article_id:{{ article_obj.pk }}
                },
                success: function (comment_list) {
                    console.log(comment_list)
    
                    $.each(comment_list, function (index, comment_object) {
                        var pk = comment_object.pk
                        var content = comment_object.content
                        var parent_comment_id = comment_object.parent_comment_id
    
                        var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span>' + '</div>'
    
                        if (!parent_comment_id) {
                            //根评论展示
                            $(".comment_tree").append(s)
    
                        } else {
                            //子评论展示
                            $("[comment_id="+parent_comment_id+ "]").append(s)
                        }
    
                    })
                }
            })
        })

     

     5、评论之事务操作

      事务同步:同进同退

    6、邮件发送评论

    django中配置邮件 

    https://blog.csdn.net/xinxinnogiveup/article/details/78900811

    https://code.ziqiangxuetang.com/django/django-send-email.html

    1、settings配置

    # 发送邮件
    EMAIL_USE_SSL = True
    # EMIAL_HOST = 'smtp.exmail.qq.com'       # 如果是163 改成smtp.163.com
    EMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.com
    EMAIL_PORT = 465
    EMAIL_HOST_USER = '7xxxxxxxx@qq.com'        # 账号
    EMAIL_HOST_PASSWORD = 'oXXXXXxxxxx'    # qq邮箱的授权码而不是密码
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER 

    qq邮箱授权码如何开启?

     http://service.mail.qq.com/cgi-bin/help?id=28&no=1001256&subtype=1

     

    2、from django.core.mail import send_mail

    3、多进程实现

     

     6、评论的完整代码

    url

        # 个人站点页面设计
        re_path(r'^(?P<username>w+)$', views.home_site, name='home_site'),
        # 个人站点的跳转
        re_path(r'^(?P<username>w+)/(?P<condition>tag|category|archive)/(?P<param>.*)/$', views.home_site, name='home_site'),
    
    
        # 文章详情页
        re_path(r'^(?P<username>w+)/articles/(?P<article_id>d+)$', views.article_detail, name='article_detail'),
    
        # 点赞
        re_path('^digg/$', views.digg, name='digg'),
    
        # 评论
        re_path('^comment/$', views.comment, name='comment'),
        # 评论树
        re_path('^get_comment_tree/$', views.get_comment_tree, name='get_comment_tree'),
    View Code

    settings

    LANGUAGE_CODE = 'en-us'
    
    
    # 时区选择
    # TIME_ZONE = 'UTC'
    TIME_ZONE = 'Asia/Shanghai'
    
    USE_I18N = True
    
    USE_L10N = True
    
    # 转换时区
    # USE_TZ = True
    USE_TZ = False
    
    
    
    # 发送邮件
    EMAIL_USE_SSL = True
    # EMIAL_HOST = 'smtp.exmail.qq.com'       # 如果是163 改成smtp.163.com
    EMAIL_HOST = 'smtp.qq.com'  # 如果是 163 改成 smtp.163.com
    EMAIL_PORT = 465
    EMAIL_HOST_USER = '7fadfasas0@qq.com'        # 账号
    EMAIL_HOST_PASSWORD = 'ord大师傅bdie'    # qq邮箱的授权码而不是密码
    DEFAULT_FROM_EMAIL = EMAIL_HOST_USER
    View Code

    view视图

    from django.shortcuts import render, HttpResponse, redirect
    from blog.utils.validCode import get_validCode_img  # 导入验证码函数
    from django.http import JsonResponse  # Json数据返回到前端
    from django.contrib import auth  # 用户认证组件
    from blog.models import UserInfo
    from blog.myForms import UserForm  # froms组件
    from blog import models
    from django.db.models import Avg, Max, Min, Count, F, Q
    from django.db import transaction  # 事务操作
    
    
    
    def article_detail(request, username, article_id):
        """文章详情页"""
        user_obj = models.UserInfo.objects.filter(username=username).first()
        blog = user_obj.blog
    
        # article_id对应的文章
        article_obj = models.Article.objects.filter(pk=article_id).first()
    
        # 评论显示
        comment_list = models.Comment.objects.filter(article_id=article_id)
    
        return render(request, 'blog/article_detail.html', locals())
    
    
    import json
    
    
    def digg(request):
        """点赞视图"""
        # print(request.POST)
        article_id = request.POST.get("article_id")
        # article_id = request.POST.get("is_up")       # true
        is_up = json.loads(request.POST.get("is_up"))  # True
        user_id = request.user.pk  # 点赞人即为登录人
    
        # 点赞记录以及存在
        from django.http import JsonResponse  # Json数据返回到前端
        response = {"state": True, "msg": None, "handled": None}
    
        obj = models.ArticleUpDown.objects.filter(user_id=user_id, article_id=article_id).first()
        if not obj:
            # 创建一条点赞记录
            ard = models.ArticleUpDown.objects.create(user_id=user_id, is_up=is_up, article_id=article_id)
            from django.db.models import F
            # 点赞数的保存
            queryset = models.Article.objects.filter(pk=article_id)
            if is_up:
                queryset.update(up_count=F("up_count") + 1)
            else:
                queryset.update(down_count=F("down_count") - 1)
        else:
            response['state'] = False
            response['handled'] = obj.is_up
    
        return JsonResponse(response)
    
    
    def comment(request):
        """评论视图"""
        article_id = request.POST.get("article_id")
        content = request.POST.get("content")
        parent_id = request.POST.get("parent_id")
        user_id = request.user.pk
    
        article_obj = models.Article.objects.filter(pk=article_id).first()
    
        with transaction.atomic():  # 事务操作
            # 创建一条评论
            comment_obj = models.Comment.objects.create(user_id=user_id, article_id=article_id,
                                                        content=content, parent_comment_id=parent_id)
            # yun   # 事务中断
            # 评论 comment_count  +1
            models.Article.objects.filter(pk=article_id).update(comment_count=F("comment_count") + 1)
    
        # 发送邮件
        from django.core.mail import send_mail
        from cnblog import settings
        """
        send_mail(
            "你的文章【%s】新增了一条评论内容" % article_obj.title,
            content,
            settings.EMAIL_HOST_USER,
            ['849923747@qq.com']
    
        )
    """
    
        import threading  # 多进程发送邮件
        t = threading.Thread(target=send_mail, args=("你的文章【%s】新增了一条评论内容" % article_obj.title,
                                                     content,
                                                     settings.EMAIL_HOST_USER,
                                                     ["849923747@qq.com"]
                                                     ))
        t.start()
    
    
        response = {}
        response["create_time"] = comment_obj.create_time.strftime("%Y-%m-%d %X")
        response["username"] = request.user.username
        response["content"] = content
    
        return JsonResponse(response)
    
    
    def get_comment_tree(request):
        """评论树"""
        article_id = request.GET.get("article_id")
        ret = list(models.Comment.objects.filter(article_id=article_id).order_by("pk").values("pk", "content",
                                                                                              "parent_comment_id"))
    
        return JsonResponse(ret, safe=False)
    View Code

    templatetags/my_tags

    # -*- coding: utf-8 -*-
    # @Time    : 2018/08/04 0004 22:03
    # @Author  : Venicid
    
    from django import template
    from django.db.models import Count
    from blog import models
    
    register = template.Library()
    
    @register.inclusion_tag("blog/classification.html")
    def get_classification_style(username):
    
        user_obj = models.UserInfo.objects.filter(username=username).first()
        blog = user_obj.blog
        cate_list = models.Category.objects.filter(blog=blog).values('pk').annotate(c=Count("article__title")).values_list("title", 'c')
        tag_list = models.Tag.objects.filter(blog=blog).values('pk').annotate(c=Count('article')).values_list('title','c')
        date_list = models.Article.objects.filter(user=user_obj).extra(select={'y_m_date':"date_format(create_time,'%%Y-%%m')"}).values('y_m_date').annotate(c=Count('nid')).values_list('y_m_date', 'c')
    
        return {'blog':blog,"tag_list":tag_list,"date_list":date_list, "cate_list":cate_list}
    
    
    
    @register.simple_tag
    def multi_tag(x,y):
    
        return x*y
    View Code

    .模板层

    article_detail.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap3/css/bootstrap.css">
        <script src="/static/js/jquery-3.2.1.min.js"></script>
        <style type="text/css">
            .glyphicon-comment {
                vertical-align: -1px;
            }
    
            #div_digg {
                float: right;
                margin-bottom: 10px;
                margin-right: 30px;
                font-size: 12px;
                width: 125px;
                text-align: center;
                margin-top: 10px;
            }
    
            .diggit {
                float: left;
                width: 46px;
                height: 52px;
                background: url('/static/img/upup.gif') no-repeat;
                text-align: center;
                cursor: pointer;
                margin-top: 2px;
                padding-top: 5px;
            }
    
            .buryit {
                float: right;
                margin-left: 20px;
                width: 46px;
                height: 52px;
                background: url('/static/img/downdown.gif') no-repeat;
                text-align: center;
                cursor: pointer;
                margin-top: 2px;
                padding-top: 5px;
            }
    
            #digg_tips {
                color: red;
                clear: both;
            }
    
            input.author {
                background-image: url('/static/img/icon_form.gif');
                background-repeat: no-repeat;
                border: 1px solid #ccc;
                padding: 4px 4px 4px 30px;
                width: 230px;
            }
    
            .comment_content {
                margin-top: 5px;
            }
    
            .reply_btn {
                color: #369;
                cursor: pointer;
    
            }
            .comment_item{
                margin-left: 20px;
            }
        </style>
    </head>
    <body>
    
    
    <div class="site-header">
        <nav class="navbar navbar-inverse">
            <div class="container-fluid">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#">
                        {{ blog.title }}
                    </a>
                </div>
                <div class="navbar-header pull-right">
                    <a class="navbar-brand" href="#">
                        管理
                    </a>
                </div>
            </div>
        </nav>
    
    </div>
    
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-3">
                {% load my_tags %}
    
                {% get_classification_style username %}
            </div>
    
    
            <div class="col-md-8">
                {% csrf_token %}
                <div class="article_info ">
                    <h3 class="text-center">{{ article_obj.title }}</h3>
                    <div> {{ article_obj.content|safe }}</div>
    
                    <div class="clearfix">
                        <div id="div_digg">
                            <div class="diggit action">
                                <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span>
                            </div>
                            <div class="buryit action">
                                <span class="burynum" id="bury_count">0</span>
                            </div>
                            <div class="clear"></div>
                            <div class="diggword" id="digg_tips"></div>
                        </div>
                    </div>
    
                    <div class="comments list-group">
                        <p class="tree_btn">评论树</p>
                        <div class="comment_tree">
    
                            <div class="comment_tree">
    
                            </div>
                        </div>
    
    
                        <p>评论列表</p>
                        <ul class="list-group comment_list">
                            {% for comment in comment_list %}
                                <li class="list-group-item">
                                    <div class="comment_head">
                                        <a href=""># {{ forloop.counter }}楼</a>&nbsp;&nbsp;
                                        <span>{{ comment.create_time|date:"Y-m-d H:i" }}</span>&nbsp;&nbsp;
                                        <a href="">{{ comment.user.username }}</a>
                                        <span class="pull-right reply_btn" username="{{ comment.user.username }}"
                                              parent_comment_pk="{{ comment.pk }}">回复</span>
                                    </div>
    
                                    {% if comment.parent_comment_id %}
                                        <div class="parent_info well">
                                            <p>{{ comment.parent_comment.user.username }}:{{ comment.parent_comment.content }}</p>
                                        </div>
                                    {% endif %}
    
                                    <div class="comment_content">
                                        <p>{{ comment.content }}</p>
                                    </div>
    
                                </li>
                            {% endfor %}
    
                        </ul>
    
                        <p>发表评论</p>
                        <p>昵称</p><input type="text" id="tbCommentAuthor" class="author" disabled="disabled" size="50"
                                        value="{{ request.user.username }}">
                        <p>评论内容</p>
                        <textarea name="" id="comment_content" cols="60" rows="10"></textarea>
                        <p>
                            <button class="btn btn-default comment_btn">提交评论</button>
                        </p>
                    </div>
    
                </div>
            </div>
        </div>
    </div>
    
    <script>
        //点赞请求
        $("#div_digg .action").click(function () {
            var is_up = $(this).hasClass("diggit");
    
            $obj = $(this).children("span");        // 获取点赞数
    
            $.ajax({
                url: "/digg/",
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                    "is_up": is_up,
                    "article_id":{{ article_obj.pk }}
                },
                success: function (data) {
                    // 点赞 +1
                    if (data.state) {
                        var val = parseInt($obj.text());
                        $obj.text(val + 1)
    
                    } else {
    
                        //点赞过了
                        var val = data.handled ? "您已经推荐过了" : "您已经反对过了"
                        $('#digg_tips').html(val)
    
                        setTimeout(function () {
                            $("#digg_tips").html("")
                        }, 2000)
                    }
                }
            })
        })
    
        //评论请求
        var parent_id = "";
    
        $('.comment_btn').click(function () {
            var content = $("#comment_content").val()
    
            if (parent_id) {
                var index = content.indexOf("
    ")
                content = content.slice(index + 1)
            }
    
            $.ajax({
                url: '/comment/',
                type: "post",
                data: {
                    "csrfmiddlewaretoken": $("[name='csrfmiddlewaretoken']").val(),
                    "article_id":{{ article_obj.pk }},
                    "content": content,
                    "parent_id": parent_id
    
                },
                success: function (data) {
                    console.log(data);
    
                    // dom操作  es6  标签字符串
                    var create_time = data.create_time
                    var username = data.username
                    var content = data.content
    
                    var s = `
                            <li class="list-group-item">
                                <div class="comment_head">
                                    <span>${create_time}</span>&nbsp;&nbsp;
                                    <a href="">${username}</a>
                                    <a class="pull-right">回复</a>
                                </div>
    
                                <div class="comment_content">
                                    <p>${content}</p>
                                </div>
                            </li>`;
    
    
                    $("ul.comment_list").append(s)
    
                    //清空评论框
                    parent_id = ""
                    $("#comment_content").val("")
                }
            })
    
    
        })
    
        //回复按钮事件
        $(".reply_btn").click(function () {
    
            $("#comment_content").focus()
            var val = "@" + $(this).attr("username") + "
    ";
            $("#comment_content").val(val)
    
            parent_id = $(this).attr("parent_comment_pk")
    
        })
    
    
        //评论树
        $(".tree_btn").click(function () {
            $.ajax({
                url: "/get_comment_tree/",
                type: "get",
                data: {
                    article_id:{{ article_obj.pk }}
                },
                success: function (comment_list) {
                    console.log(comment_list)
    
                    $.each(comment_list, function (index, comment_object) {
                        var pk = comment_object.pk
                        var content = comment_object.content
                        var parent_comment_id = comment_object.parent_comment_id
    
                        var s = '<div class="comment_item" comment_id=' + pk + '><span>' + content + '</span>' + '</div>'
    
                        if (!parent_comment_id) {
                            //根评论展示
                            $(".comment_tree").append(s)
    
                        } else {
                            //子评论展示
                            $("[comment_id="+parent_comment_id+ "]").append(s)
                        }
    
                    })
                }
            })
        })
    
    </script>
    </body>
    </html>
    View Code

    classifications.html

            <div>
                <div class="panel panel-warning">
                    <div class="panel-heading">我的标签</div>
                    <div class="panel-body">
                        {% for tag in tag_list %}
                            <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">随笔分类</div>
                    <div class="panel-body">
                        {% for cate in cate_list %}
                            <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">随笔归档</div>
                    <div class="panel-body">
                        {% for date in date_list %}
                            <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
            </div>
    View Code

    home_site.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
        <link rel="stylesheet" href="/static/bootstrap3/css/bootstrap.css">
        <style type="text/css">
            .glyphicon-comment {
                vertical-align: -1px;
            }
        </style>
    </head>
    <body>
    <div class="site-header">
        <nav class="navbar navbar-inverse">
            <div class="container-fluid">
                <div class="navbar-header">
                    <a class="navbar-brand" href="#">
                        {{ blog.title }}
                    </a>
                </div>
                <div class="navbar-header pull-right">
                    <a class="navbar-brand" href="#">
                        管理
                    </a>
                </div>
            </div>
        </nav>
    
    </div>
    
    <div class="container-fluid">
        <div class="row">
            <div class="col-md-3">
                <div class="panel panel-warning">
                    <div class="panel-heading">我的标签</div>
                    <div class="panel-body">
                        {% for tag in tag_list %}
                            <p><a href="/{{ username }}/tag/{{ tag.0 }}">{{ tag.0 }}({{ tag.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
    
                <div class="panel panel-warning">
                    <div class="panel-heading">随笔分类</div>
                    <div class="panel-body">
                        {% for cate in cate_list %}
                            <p><a href="/{{ username }}/category/{{ cate.0 }}">{{ cate.0 }}({{ cate.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
                <div class="panel panel-warning">
                    <div class="panel-heading">随笔归档</div>
                    <div class="panel-body">
                        {% for date in date_list %}
                            <p><a href="/{{ username }}/archive/{{ date.0 }}">{{ date.0 }}({{ date.1 }})</a></p>
                        {% endfor %}
    
                    </div>
                </div>
            </div>
            <div class="col-md-8">
                {% for article in article_list %}
                    <div class="article-item clearfix">
                        <h5><a href="">{{ article.title }}</a></h5>
                        <div class="article-desc">
                            <span>{{ article.desc }}</span>
                        </div>
                        <div class="small pub_info pull-right ">
                            <span>发布于&nbsp;&nbsp;{{ article.create_time|date:"Y-m-d H:m:s" }}</span>&nbsp;&nbsp;&nbsp;
                            <span class="glyphicon glyphicon-comment">评论({{ article.comment_count }})</span>&nbsp;&nbsp;&nbsp;
                            <span class="glyphicon glyphicon-thumbs-up">点赞({{ article.up_count }})</span>
                        </div>
                    </div>
                    <hr>
                {% endfor %}
    
            </div>
        </div>
    </div>
    
    </body>
    </html>
    View Code
  • 相关阅读:
    JNI和NDK编程
    View的弹性滑动
    View的滑动
    《软件项目管理》课程
    《软件测试》课堂笔记05
    “MAVEN” 简单入门
    “Junit” 简单测试
    关于“百合测试”的实例
    关于“黑盒测试”的实例
    《软件测试》课堂笔记04
  • 原文地址:https://www.cnblogs.com/venicid/p/9428968.html
Copyright © 2020-2023  润新知