summerdawn文章评论调整

linxiaoyun 2018.2.23 13:03 1308 5
summerdawn Django

django-comments提供的评论只有一个层级。如果对评论进行回复需要对包文件进行修改。从MVC的角度出发,略微记录一下修改。

1.目录templatetags是comments库的自定义标签处理的文件夹,文件templatetags/comments.py 包含自定义标签的处理方法

2.目录views是comments库的相关响应方法,文件views/comments.py 包括评论库的主要处理方法

3、文件models.py 评论库的模型文件

一、呈现的效果

包括评论文章,有相应序号,回复评论,缩进依次显示。

二、模型model需增加三个字段

根据Comment类的定义,在CommentAbstractModel类中添加:

    #修改2018年2月9日
    root_id =models.IntegerField(default=0)
    reply_to =models.IntegerField(default=0)
    reply_name=models.CharField(max_length=50,blank=True)

root_id:这个字段是标记回复的一开始是哪个评论。因为回复也可能回复其他人的回复,这些回复都会放在一个评论下面,所以就加这个字段标记一下。

reply_to: 这个字段就是直接标记回复哪个评论或者回复了。

reply_name: 回复哪个评论或者回复的帐号名。虽然这个账号名和通过comment对象获取找到对应的名称,但这个需要写比较多的代码,还是直接写到数据库中,方便获取。

三、控制views/comments需要处理相应字段

    #增加 2018年2月10日
    comment.root_id = data.get('root_id',0)
    comment.reply_to = data.get('reply_to',0)
    comment.reply_name = data.get('reply_name','')

    if user_is_authenticated:
        comment.user = request.user

这个是把我们前面加的字段写入数据。

四、修改自定义标签comments,为视图提供内容

在/home/liulinhai/blog_env/lib/python3.5/site-packages/django_comments/templatetags/comments.py中,修改get_queryset函数

    def get_queryset(self, context):
        ctype, object_pk = self.get_target_ctype_pk(context)
        if not object_pk:
            return self.comment_model.objects.none()

        # Explicit SITE_ID takes precedence over request. This is also how
        # get_current_site operates.
        site_id = getattr(settings, "SITE_ID", None)
        if not site_id and ('request' in context):
            site_id = get_current_site(context['request']).pk

        qs = self.comment_model.objects.filter(
            content_type=ctype,
            object_pk=smart_text(object_pk),
            site__pk=site_id,
            root_id=0,#增加2018年2月10日
        )

        # The is_public and is_removed fields are implementation details of the
        # built-in comment model's spam filtering system, so they might not
        # be present on a custom comment model subclass. If they exist, we
        # should filter on them.
        field_names = [f.name for f in self.comment_model._meta.fields]
        if 'is_public' in field_names:
            qs = qs.filter(is_public=True)
        if getattr(settings, 'COMMENTS_HIDE_REMOVED', True) and 'is_removed' in field_names:
            qs = qs.filter(is_removed=False)
        if 'user' in field_names:
            qs = qs.select_related('user')

        #增加2018年2月10日
        for q in qs:
            q.replies=self.comment_model.objects.filter(
                content_type=ctype,
                object_pk=smart_text(object_pk),
                site__pk=site_id,
                root_id=q.id,
                is_public=True,
                is_removed=False,
            ).order_by('submit_date')
            #动态增加replies属性
        return qs

其中,self.comment_model是评论模型的对象,通过这个对象获取内容。第1个修改的地方是给第1次获取评论的地方加上条件 root_id=0,这样获取到的记录都是评论。

第2个修改的地方在该方法末尾。循环遍历所有相关评论,获取对应的回复。这里利用python的语音特性,动态加了replies属性,该属性用于获取该评论的所有回复。(详见杨仕航的博客

五、评论呈现及样式

在detail2.html模板中修改评论显示

   <div class="panel panel-default">
        <div class="panel-heading">
            <a id="jump_to_comment" title="我要评论"><h4>评论列表</h4></a>
        </div>

        <div class="panel-body">
            {% get_comment_list for post as comments %}
            {% for comment in comments %}
                <div class="blog_comment" name="F{{comment.id}}">
                    <p class="comment_title">{{ comment.user_name }}:<span style="float:right">{{ forloop.counter }}#</span>
                    </p>
                    <div class="comment_content"> {{ comment.comment|safe }}</div>
                    <p class="comment_bottom">
                        <span>{{ comment.submit_date|date:"Y年n月j日 G:i"}}</span>
                        <span class='reply_button'>
                        <a href='javascript:void(0);' onclick='reply_click(this);' root='{{comment.id}}' role='{{comment.id}}' base='{{comment.user_name}}'><i class="fa fa-share fa-border" aria-hidden="true">回复</i></a>
                        </span>
                    </p>

                    {% if comment.replies %}
                    <ul class="comment_reply">
                        {% for reply in comment.replies %}
                        <li name='F{{ reply.id }}'>
                            <div class='reply_body'>
                                 <p>
                                    {#判断是否回复评论#}
                                    {% ifequal reply.user_name reply.reply_name %}
                                        <span class="reply_name">{{reply.user_name}}</span>
                                        <i class="fa fa-share" aria-hidden="true"></i>
                                    {% else %}
                                        <span class="reply_name">{{reply.user_name}}</span>
                                        <i class="fa fa-share" aria-hidden="true"></i>
                                        <span class="reply_name">{{reply.reply_name}}</span>
                                    {% endifequal %}
                                </p>
                                <div class="reply_content">
                                <p>{{ reply.comment }}</p>
                                </div>
                                <p class="comment_bottom">
                                    <span>{{reply.submit_date|date:"Y年n月j日 G:i"}}</span>
                                    <span class='reply_button'>
                                    <a href='javascript:void(0);' onclick='reply_click(this);' root='{{reply.root_id}}' role='{{reply.id}}' base='{{reply.user_name}}'><i class="fa fa-share fa-border" aria-hidden="true">回复</i></a>
                                    </span>
                                </p>
                            </div>
                        </li>
                        {% endfor %}
                    </ul>
                    {% endif %}
                    <hr>
                </div>

            {% empty %}
                暂无评论
            {% endfor %}
        </div>
    </div>
                        

其中点击事件处理函数为,当为回复评论时设置相应的root_id和reply_to,否则为评论文章,设置root_id为0。与前面自定义标签函数get_queryset的过滤参数一致。

//回复按钮点击事件
function reply_click(obj){
    obj = $(obj);
    if(obj.text()=="回复"){
        //展开回复框
        obj.html("<i class=\"fa fa-angle-double-up fa-border\" aria-hidden=\"true\">收起</i>");

        $("#reply_form").hide();
        obj.after($("#reply_form"));
        $("#reply_form").slideDown(200);

        $("#reply_to").val(obj.attr("role"));
        $("#root_id").val(obj.attr("root"));
        $("#reply_name").val(obj.attr("base"));
        $(".comment_text").focus();
    }else{
        //收起回复框
         obj.html("<i class=\"fa fa-share fa-border\" aria-hidden=\"true\">回复</i>");
        $("#reply_form").hide();
         $("#reply_to").val('0');
         $("#root_id").val('0');
         $("#reply_name").val("");
        $("#reply_content").append($("#reply_form"));
        $("#reply_form").slideDown(200);
        $(".comment_text").focus();
    }

    return false;
}

其中样式表的CSS为:

.comment_text{ width: 100%; height: 9em; overflow-y: visible;}
.comment_button{ margin-top:0.5em; float: right;}
.btn{border-radius: 3px;padding: 5px 10px;border: 1px solid #ddd;font-size: 85%;margin-right:15px}

.blog_comment p{ margin: 10px;}
.blog_comment .comment_title { margin:0;}
.blog_comment .comment_bottom { margin:0;text-align:right;font-size:18px;}
p.comment_bottom span:first-child {opacity:0.5;}

.blog_comment .reply_body p{ margin: 0;}
.blog_comment .comment_reply{ border-top: 1px #ddd dashed; padding-top: 0.2em;}
.blog_comment .comment_reply li{  list-style:none;}

六、新评论发表

模板文件为:

        <div class="container">
            <div class="row">
                <div id="reply_content" class="col-lg-8 col-lg-offset-2 col-md-10 col-md-offset-1">
    <div class="comments_nav" id="reply_form" style="display:block;text-indent:0;">
        {% if user.is_authenticated %}
    {% if user.is_active %}

        <h4>新的评论</h4>
        {% get_comment_form for post as blog_form %}
            <form class="form-horizontal" action="#" method="post" id="comment_form">
        {% csrf_token %}

        {{ blog_form.object_pk }}
        {{ blog_form.content_type }}
        {{ blog_form.timestamp }}
        {{ blog_form.site }}
        {{ blog_form.submit_date }}
        {{ blog_form.security_hash }}


        <input type="hidden" name="next" value="{% url 'blog:detail' post.id %}"/>
        <input id="reply_to" type="hidden" name="reply_to" value="0" />
        <input id="root_id" type="hidden" name="root_id" value="0" />
        <input id="reply_name" type="hidden" name="reply_name" value="">

        <div class="row">
            <div class="col-lg-12 col-md-12 ">
                <textarea class="input-xlarge comment_text" id="id_comment" name="comment" placeholder="为了防止垃圾评论,需要登录,才能评论哦~"></textarea>

                <!--如果你在该字段中输入任何内容,你的评论就会被视为垃圾评论-->
                <input type="text" style="display:none;" id="id_honeypot" name="honeypot">
            </div>
        </div>

        <div class="row">
              <div class="form-actions comment_button" style="float:right;">
                <span id='tip_text'></span>
                <button class="btn" id="submit_btn" type="submit" name="submit" value="提交" >
                  <i class="fa fa-paper-plane" aria-hidden="true" ></i>
                    发布
                </button>
              </div>

        </div>
     </form>
                                {% else %}
                    您尚未激活,请先激活您的账户才能评论。(避免垃圾评论)
                {% endif %}
                {% else %}
                    <p style="text-align:center">您尚未登录,请先<a href="{%url 'admin:login' %}?next={{post.get_absolute_url}}"><i class="fa fa-sign-in fa-border " aria-hidden="true">登录</i></a>才能评论。</p>
                {% endif %}
    </div>

                      </div>
                    </div>
                </div>

其中,切换回复评论框位置详见上述reply_click。使用after和append命令。

Last Modified·2018年2月24日 12:32

linxiaoyun:1#

整理完这篇年前的文章,summerdawn网站进入的版本2.0。主要更新有:1.更快的访问速度,服务器移至国内阿里云;2.评论分级显示,修改django-comment包,使其支持评论回复,并采用ajax技术提交;3.增加搜文功能,根据文章标题和内容进行关键词搜索。

2018年2月23日 16:54


admin:2#

不错,很棒。2018年是奋斗的一年,网站已经稳定,还有更重要的任务。切换状态也是能力。加油!!!

2018年2月23日 16:56


linxiaoyun:3#

还增加了zoom.js图片缩放功能。

2018年2月24日 12:24


dengli:4#

很棒,一起加油!!!

2018年2月25日 0:04


linxiaoyun:5#

为了不验证邮箱,同时评论并未开放邮箱填写,故需要在forms.py文件的class CommentDetailsForm(CommentSecurityForm)类定义中,给email字段添加required=False的要求: email = forms.EmailField(label=_("Email address"),required=False)

2021年11月27日 20:57


您尚未登录,请先才能评论。