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
您尚未登录,请先登录才能评论。