利用medeitor配置评论功能、留言模块

2020年6月2日 00:40 阅读 670 评论 1

用户和博文的交互和用户和用户的交互都离不开评论、留言功能,这里我们结合之前的代码,继续利用mdeditor包来开发评论和留言。

创建网站评论的基类model并进行扩展

对于评论的积累,我们需要创建评论发起的作者、创建日期/时间、评论的内容、父级评论、回复的评论、和一个content_to_markdown函数用于返回将markdown转化为html代码的数据,其中多个相互回复的评论可能都属于同一个父级评论比如这样:

model中的基类代码 apps\comment\models.py

from django.db import models
from django.conf import settings
from apps.blog.models import Article
from mdeditor.fields import MDTextField

import markdown
import emoji

class Comment(models.Model):
    author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='%(class)s_related', verbose_name='评论人',null=False, default='2')
    create_date = models.DateTimeField('创建时间', auto_now_add=True)
    content = MDTextField('评论内容')
    parent = models.ForeignKey('self', verbose_name='父评论',on_delete=models.CASCADE, related_name='%(class)s_child_comments', blank=True,
                               null=True)
    rep_to = models.ForeignKey('self', verbose_name='回复',on_delete=models.CASCADE, related_name='%(class)s_rep_comments', blank=True, null=True)

    class Meta:
        '''这是一个元类,用来继承的'''
        abstract = True

    def __str__(self):
        return self.content[:20]

    def content_to_markdown(self):
        # 先转换成emoji然后转换成markdown,'escape':所有原始HTML将被转义并包含在文档中
        to_emoji_content = emoji.emojize(self.content, use_aliases=True)
        to_md = markdown.markdown(to_emoji_content,
                                  safe_mode='escape',
                                  extensions=[
                                      'markdown.extensions.extra',
                                      'markdown.extensions.codehilite',
                                  ])
        return to_md

继承基类评论扩展文章评论类

文章评论中我们需要扩展一个字段为belong表示所属文章信息,方便我们在同类文章中显示同类的评论。 model中扩展代码apps\comment\models.py

# 文章评论
class ArticleComment(Comment):
    belong = models.ForeignKey(Article,on_delete=models.CASCADE, related_name='article_comments', verbose_name='所属文章',null=False, default='4')

    class Meta:
        verbose_name = '文章评论'
        verbose_name_plural = verbose_name
        ordering = ['create_date']

扩展留言板功能

留言板只需要涉及到用户和用户之间的交互,继承代码如下: apps\comment\models.py

# 留言板
class Message(Comment):
    author = models.ForeignKey(settings.AUTH_USER_MODEL,on_delete=models.CASCADE, related_name='related', verbose_name='评论人',null=False, default='2')
    parent = models.ForeignKey('self', verbose_name='父评论',on_delete=models.CASCADE, related_name='child_messages', blank=True,
                               null=True)

    rep_to = models.ForeignKey('self', verbose_name='回复',on_delete=models.CASCADE, related_name='rep_messages', blank=True, null=True)
    class Meta:
        verbose_name = '网站留言'
        verbose_name_plural = verbose_name
        ordering = ['create_date']

视图view和前端代码html

前后端我们使用得常规得ajax组装请求发送到view设计的url中,进行数据传输,这里我们主要开发四个view视图,分别是,留言板的展示、文章评论的展示、留言评论信息的删除撤回和增加功能。 editor.md项目包中介绍了基础的配置和用法,https://github.com/pandao/editor.md 感兴趣的可以下载demo玩玩看。 继承上次我们开发的图片上传的路由:http://127.0.0.1:8000/article/editor-md-nian-tie-tu-pian-de-cha-jian-kai-fa/

设计按钮点击交互ajax传输

界面交互需求大致如下 - 点击发送,获取评论信息、评论的文章(没有就为空)、回复的对象id、和评论人id - 点击回复按钮、点击取消回复按钮 - 撤销消息按钮(超时而不能发送我们在前端用python的tags函数来实现) 源码static\comment\js\message.js

    $(function() {
    //    点击回复
        $(".rep-btn").click(function(){
            var u = $(this).data('repuser')
            var i = $(this).data('repid')
            sessionStorage.setItem('rep_id', i);
            $("#rep-to").text("回复 @"+u).removeClass('hidden');
            $("#no-rep").removeClass('hidden');
            $(".rep-btn").css("color", "#868e96");
            $(this).css("color", "red");
            $('html, body').animate({
                scrollTop: $($.attr(this, 'href')).offset().top - 55
            }, 500);
        });
    //    点击取消回复
        $("#no-rep").click(function(){

            sessionStorage.removeItem('rep_id');
            $("#rep-to").text('').addClass('hidden');
            $("#no-rep").addClass('hidden');
            $(".rep-btn").css("color", "#868e96");
        });
    //    点击提交留言
        $("#push-message").click(function(e) {
            // 获取留言的内容
            var content = $("#mdeditor").val();

            if (content.length == 0) {
                alert("留言内容不能为空!");
                return;
            }
            var base_t = sessionStorage.getItem('base_t');
            var now_t = Date.parse(new Date());
            if (base_t) {
                var tt = now_t - base_t;
                // if (tt < 40000) {
                //     alert('两次留言时间间隔必须大于40秒,还需等待' + (40 - parseInt(tt / 1000)) + '秒');
                //     return;
                // } else {
                //     sessionStorage.setItem('base_t', now_t);
                // }
                sessionStorage.setItem('base_t', now_t);
            } else {
                sessionStorage.setItem('base_t', now_t)
            };
            var csrf = $(this).data('csrf');
            var URL = $(this).data('ajax-url');
            var rep_id = sessionStorage.getItem('rep_id');
            var article_id = $(this).data('article-id');
            $.ajaxSetup({
                data: {
                    'csrfmiddlewaretoken': csrf
                }
            });
            $.ajax({
                type: 'post',
                url: URL,
                data: {
                    'rep_id': rep_id,
                    'content': content,
                    'article_id': article_id
                },

                dataType: 'json',
                success: function(ret) {
                    sessionStorage.removeItem('rep_id');
                    sessionStorage.setItem('new_point', ret.new_point);
                    window.location.reload();
                },
                error: function(ret) {
                    alert(ret.msg);
                }
            });
        });
    //    点击撤回评论
        $(".del-message").click(function(e) {
            var csrf = $(this).data('csrf');
            var URL = $(this).data('ajax-url');
            var mes_id = $(this).data('mes-id');
            var article_id = $(this).data('article-id');
            console.log(article_id)
            $.ajaxSetup({
                data: {
                    'csrfmiddlewaretoken': csrf
                }
            });
            $.ajax({
                type: 'post',
                url: URL,
                data: {
                    'mes_id': mes_id,
                    'article_id': article_id
                },

                dataType: 'json',
                success: function(ret) {
                    window.location.reload();
                    window.location.hash = "#mdeditor";
                },
                error: function(ret) {
                    alert(ret.msg);
                }
            });
        });
    //    提交留言后定位到新留言处
        if (sessionStorage.getItem('new_point')) {
            console.log(sessionStorage.getItem('new_point'))
            // $('body,html').animate({scrollTop: $(sessionStorage.getItem('new_point')).offset().top}, 500);
            window.location.hash = sessionStorage.getItem('new_point');
            sessionStorage.removeItem('new_point');
        };
        sessionStorage.removeItem('rep_id');
})

调用jq库,使用// 获取留言的内容var content = $("#mdeditor").val();调用textarea中id为mdeditor中的markdown数据。

获取其他需要的数据,当我们对文章进行

var base_t = sessionStorage.getItem('base_t');
        var now_t = Date.parse(new Date());
        if (base_t) {
            var tt = now_t - base_t;
            // if (tt < 40000) {
            //     alert('两次留言时间间隔必须大于40秒,还需等待' + (40 - parseInt(tt / 1000)) + '秒');
            //     return;
            // } else {
            //     sessionStorage.setItem('base_t', now_t);
            // }
            sessionStorage.setItem('base_t', now_t);
        } else {
            sessionStorage.setItem('base_t', now_t)
        };
        var csrf = $(this).data('csrf');
        var URL = $(this).data('ajax-url');
        var rep_id = sessionStorage.getItem('rep_id');
        var article_id = $(this).data('article-id');

设计前端评论框编辑界面

代码一部分继承之前md2html界面的开发的代码、一部分添加界面新得业务逻辑。我们构建一个前端可以编辑的editor.md框框: 在templates\comment\message_form.html

{% load static %}
{% if user.is_authenticated %}
{% block top_file %}
    <style type="text/css">
        #message-meditor {
            z-index: 100;
        }
    </style>
{% endblock %}

<link href="{% static 'mdeditor/css/editormd.min.css' %}" rel="stylesheet" type="text/css">
<div class="send-mgs">
    <div id="message-meditor" class="yourmsg">        
                <textarea id="mdeditor" class="form-control rounded-0" id="md_contain" placeholder="评论请使用 markdown 语法..." rows="5"></textarea>
    </div>
    <div style="overflow: hidden;">
    <button type="button" class="fa fa-paper-plane-o btn btn-info btn-lg float-right f-16"
            id="push-message" data-csrf="{{ csrf_token }}"  data-article-id="{{ article.id }}"
            data-ajax-url="{% url 'comment:add_comment' %}"></button>

    <button type="button" class="fa fa-reply btn btn-danger btn-lg float-right mr-4 f-16 hidden" id="no-rep"></button>

    <span class='float-left text-info ml-0 hidden' id='rep-to'>xxx</span>


    </div>
</div>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="{% static 'comment/js/message.js' %}"></script>
{% else %}
<div class="text-center m-2 m-md-3 f-16" id="no-editor">
    <div>您尚未登录,请
        <a class="text-danger" href="/accounts/login">登录</a><a class="text-danger" href="/accounts/signup">注册</a> 后评论
    </div>
    <div class="login-link mt-2">
        <a class="mx-3" href="/accounts/github/login/?next={{ request.path }}" title="社交账号登录有点慢,请耐心等候!"><i
                class="fa fa-github fa-2x"></i></a>
    </div>
</div>
{% endif %}
{% block end_file %}
<!-- 基础文件 -->
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
<script src="{% static 'mdeditor/js/editormd.min.js' %}"></script>
<script src="{% static 'mdeditor/js/lib/raphael.min.js' %}"></script>
<!-- 绘制序列图 -->
<script src="{% static 'mdeditor/js/lib/sequence-diagram.min.js' %}"></script>
<!-- 绘制流程图 -->
<script src="{% static 'mdeditor/js/lib/flowchart.min.js' %}"></script>
<script src="{% static 'mdeditor/js/lib/jquery.flowchart.min.js' %}"></script>
<!-- <script src="{% static 'mdeditor/js/lib/underscore.min.js' %}"></script> -->
<!-- <script src="{% static 'mdeditor/js/lib/marked.min.js' %}"></script> -->
<!-- <script src="{% static 'mdeditor/js/lib/prettify.min.js' %}"></script> -->
<script type="text/javascript">
    var testEditor;
    $(function() {    
        testEditor = editormd("message-meditor", {
            width     : "90%",
            path : "{% static 'mdeditor/js/lib/' %}",
            height    : 240,
            toc       : false,
            // //atLink    : false,    // disable @link
            // //emailLink : false,    // disable email address auto link
            syncScrolling       : 'single',
            todoList  : true,
            // theme : "dark",
            // previewTheme : "dark",
            // editorTheme : "pastel-on-dark",
            // markdown : md,
            codeFold : true,
            // //syncScrolling : false,
            saveHTMLToTextarea : true,    // 保存 HTML 到 Textarea
            searchReplace : true,
            // 开启工具栏固定定位
            toolbarAutoFixed: false,
            watch : false,                // 关闭实时预览
            // htmlDecode : "style,script,iframe|on*",            // 开启 HTML 标签解析,为了安全性,默认不开启    
            // //toolbar  : false,             //关闭工具栏
            // //previewCodeHighlight : false, // 关闭预览 HTML 的代码块高亮,默认开启
            emoji : true,
            taskList : true,
            tocm            : false,         // Using [TOCM]
            tex : true,                   // 开启科学公式TeX语言支持,默认关闭
            flowChart : true,             // 开启流程图支持,默认关闭
            sequenceDiagram : true,       // 开启时序/序列图支持,默认关闭,
            imageUpload : true,
            imageUploadURL: "/tool/default_upload/", //图片上传后台地址
            onload: function() {
                    // 界面重定位
                    var pot = window.location.hash;
                    if (pot){
                        // 重定位到界面href中的#后id值
                        console.log('重定位到',pot)
                        $('body,html').animate({scrollTop: $(pot).offset().top-100}, 500);
                    }
                    else{
                        // 重定位到界面顶端
                        $('body,html').animate({scrollTop: $("body").offset().top-100}, 1);
                    }
                    // window.location.hash = pot
                    // 引入插件 执行监听方法
                    editormd.loadPlugin("{% static 'mdeditor/js/plugins/image-handle-paste/image-handle-paste' %}", function(){
                        testEditor.imagePaste();
                    });
                }
        });


    });
</script>
{% endblock %}

前后端数据传输使用常用的ajax数据传输,启动按钮再这:

<button type="button" class="fa fa-paper-plane-o btn btn-info btn-lg float-right f-16"
            id="push-message" data-csrf="{{ csrf_token }}"  data-article-id="{{ article.id }}"
            data-ajax-url="{% url 'comment:add_comment' %}"></button>

留言板

留言板的展示通过简单的-id顺序排序tool/views.py

class MessageView(generic.ListView):
    model = Message
    template_name = 'comment/messages_board.html'
    context_object_name = 'leaved_messages'
    paginate_by = getattr(settings, 'BASE_PAGE_BY', None)
    paginate_orphans = getattr(settings, 'BASE_ORPHANS', 0)

    def get_ordering(self):
        ordering = super(MessageView, self).get_ordering()
        sort = self.kwargs.get('sort')
        if sort == 'v':
            return ('-update_date', '-id')
        return ('-id',)

留言板前端展示,集成base.html,进行开发,设计开发聊天框card界面,相应的css和js文件在githu上可以看到源码 代码如下templates\comment\messages_board.html

    {% extends "base.html" %}
    {% load comment_tags %}
    {% block head_title %}留言板,欢迎捉虫、讨论技术、Stray_Camel(^U^)ノ~YO{% endblock %}
    {% block metas %}
        <meta name="description"  content="留言板,欢迎捉虫、讨论技术、Stray_Camel(^U^)ノ~YO" />
        <meta name="keywords"  content="{{ SITE_KEYWORDS}}" />
    {% endblock %}
    {% load static %}
    {% block content %}
    <div class="card card-horizontal">
        <div class="card-body">
                <h3 class="card-title"><a href="/article/article.slug" target="_blank">留言板</a></h3>
                <div class="messenger-box">
                    {% include "comment/message_form.html" %}
                    <ul class="messege_ul">
                        {% for message in leaved_messages  %}
                        <li>
                            {% if user == message.author %}
                            <div  id="mes-{{message.id}}" class="msg-sent msg-container">
                            {% else %}
                            <div id="mes-{{message.id}}" class="msg-received msg-container">
                            {% endif %}
                                <div class="avatar">
                                   <img src="{{message.author.avatar.url}}" alt="">
                                   <div class="send-time">{{ message.create_date}}</div>
                                </div>
                                <div class="msg-box">
                                    <div class="inner-box">
                                        <div class="name">
                                            {{ forloop.revcounter0 }}&nbsp;-&nbsp;
                                            {% if message.author.is_superuser %}
                                            <small class="text-danger">[博主]</small>
                                            {% else %}
                                            <small class="text-info">[作者]</small>
                                            {% endif %}{{message.author}}
                                            {% if user == message.author %}
                                            {% recall_com message as recall_check %}
                                            {% if recall_check %}
                                            <button type="button" class="del-message mr-2 float-left" data-csrf="{{ csrf_token }}"
                                            data-ajax-url="{% url 'comment:del_comment' %}" data-mes-id="{{ message.id }}">撤回</button>
                                            {% endif %}
                                            <a class="mr-2 rep-btn float-left"  href="#message-meditor"
                               data-repid="{{ message.id }}" data-repuser="{{ message.author.username }}">回复</a>
                                            {% else %}
                                            <a class="mr-2 rep-btn float-right"  href="#message-meditor"
                               data-repid="{{ message.id }}" data-repuser="{{ message.author.username }}">回复</a>
                                            {% endif %}
                                        </div>
                                        <div class="meg">
                                            {{ message.content_to_markdown|safe}}
                                        </div>
                                        {% if message.rep_to %}
                                        <div  style="background-color:rgba(0, 0, 0, 0.1);">
                                            @<a>{{ message.rep_to.author.username }}</a><i class="fa fa-share"></i><a href="#mes-{{message.rep_to.id}}">{{message.rep_to}}</a>
                                        </div>
                                        {% endif %}
                                    </div>
                                </div>
                            </div>
                        </li>
                        {% empty %}
                        <div class="no-post">暂时还没有留言!</div>
                        {% endfor %}

                        <!-- PAGINATION -->
                        {# The following renders the pagination html #}
                        {% include "blog/_pagination.html" %}
                    </ul>
                </div><!-- /.messenger-box -->
        </div>
    </div>
    <div class="clearfix"></div>
    <!-- DIVIDER -->
    <hr class="section-divider" />
    {% endblock %}

{% if message.author.is_superuser %}判断用户是否为超级用户boot也就是我自己,

{% if user == message.author %}
{% recall_com message as recall_check %}
{% if recall_check %}
<button type="button" class="del-message mr-2 float-left" data-csrf="{{ csrf_token }}"
data-ajax-url="{% url 'comment:del_comment' %}" data-mes-id="{{ message.id }}">撤回</button>
{% endif %}
........

recall_com message as recall_check判断评论的时间是否超时,如果超时就不显示撤回按钮。只有当当前用户为作者并且没有超过时间的限制的时候才能进行撤回。

标签函数源代码如下: apps\comment\templatetags\comment_tags.py

# 创建了新的tags标签文件后必须重启服务器

from django import template
from django.utils import timezone
from ..models import Message
register = template.Library()
@register.simple_tag
.....
def recall_com(mes):
    """判断message创建日期是否为一天前"""
    time = timezone.localtime(timezone.now())
    return max((time - mes.create_date).days, 1)
....

文章界面评论功能

文章评论和留言板最大的区别就是文章评论需要关联文章id信息,而后者不用。

模型model构建

继承之前我们常见的基类、添加新的字段belong apps\comment\models.py

# 文章评论
class ArticleComment(Comment):
    belong = models.ForeignKey(Article,on_delete=models.CASCADE, related_name='article_comments', verbose_name='所属文章',null=False, default='4')

    class Meta:
        verbose_name = '文章评论'
        verbose_name_plural = verbose_name
        ordering = ['create_date']

后端通过标签函数给数据到前端

apps\comment\templatetags\comment_tags.py

# 创建了新的tags标签文件后必须重启服务器

from django import template
from django.utils import timezone
from ..models import Message
register = template.Library()

.....
@register.simple_tag
def get_comment_count(entry):
    '''获取一个文章的评论总数'''
    lis = entry.article_comments.all()
    return lis.count()

@register.simple_tag
def get_parent_comments(entry):
    '''获取一个文章的父评论列表'''
    lis = entry.article_comments.filter(parent=None)
    return lis

@register.simple_tag
def get_child_comments(com):
    '''获取一个父评论的子平路列表'''
    lis = com.articlecomment_child_comments.all()
    return lis

@register.simple_tag
def get_comment_user_count(entry):
    '''获取评论人总数'''
    p = []
    lis = entry.article_comments.all()
    for each in lis:
        if each.author not in p:
            p.append(each.author)
    return len(p)

@register.simple_tag
def get_notifications(user,f=None):
    '''获取一个用户的对应条件下的提示信息'''
    if f=='true':
        lis = user.notification_get.filter(is_read=True)
    elif f=='false':
        lis = user.notification_get.filter(is_read=False)
    else:
        lis = user.notification_get.all()
    return lis

@register.simple_tag
def get_notifications_count(user,f=None):   
    '''获取一个用户的对应条件下的提示信息总数'''
    if f=='true':
        lis = user.notification_get.filter(is_read=True)
    elif f=='false':
        lis = user.notification_get.filter(is_read=False)
    else:
        lis = user.notification_get.all()
    return lis.count()


# 留言板
@register.simple_tag
def get_message_num():
    """获取网站留言的总数"""
    return Message.objects.all().count()

@register.simple_tag
def get_message_date():
    """获取不同月份留言"""
    message_dates = Message.objects.datetimes('create_date', 'month', order='DESC')
    return article_dates

@register.simple_tag
def get_parent_message():
    '''父留言列表'''
    lis = Message.objects.filter(parent=None)
    return lis

@register.simple_tag
def get_child_messages(com):
    '''获取一个父留言的子平路列表'''
    lis = com.child_messages.all()
    return lis

@register.simple_tag
def get_message_user_count(entry):
    '''获取留言人总数'''
    p = []
    lis = Message.objects.all()
    for each in lis:
        if each.author not in p:
            p.append(each.author)
    return len(p)

文章界面评论区的展示html

templates\comment\comment_list.html

{% load static %}
{% load comment_tags oauth_tags %}
{% get_parent_comments article as comment_list %}
<div class="card-body p-2 p-md-3 f-17" id="comment-list">
    <ul class="list-unstyled">
        <div class="mb-3">
            <strong>{% get_comment_user_count article %}&nbsp;人参与&nbsp;|&nbsp;{% get_comment_count article %}&nbsp;条评论</strong>
        </div>
        {% for comment in comment_list %}
        <div class="comment-parent pt-2" id="com-{{ comment.id }}">
            <li class="media">
                {% if comment.author.socialaccount_set.exists and comment.author.avatar.url == '/media/avatar/default.png' %}
            <img class="avatar" src="{{ comment.author.socialaccount_set.all.0.get_avatar_url }}" alt="{{ comment.author }}">
            {% else %}
            <img class="avatar" src="{{ comment.author.avatar.url }}" alt="{{ comment.author }}">
            {% endif %}
                <div class="media-body ml-2">
                    {% recall_com comment as recall_check %}
                    {% if recall_check and user == comment.author %}

                    <button type="button" class="del-message mr-2 float-right" data-csrf="{{ csrf_token }}"
                    data-ajax-url="{% url 'comment:del_comment' %}" data-mes-id="{{ comment.id }}"data-mes-id="{{ each.id }}" data-article-id="{{ article.id }}">撤回</button>
                    {% endif %}
                    <a class="mr-2 rep-btn float-right"  href="#message-meditor"
                           data-repid="{{ comment.id }}" data-repuser="{{ comment.author.username }}">回复</a>
                    <p class="mt-0 mb-1">
                        <strong>{{ comment.author }}</strong>
                        {% if comment.author.is_superuser %}
                        <small class="text-danger">[博主]</small>
                        {% endif %}
                    </p>
                    <p class="small text-muted">{{ forloop.counter }}&nbsp;-&nbsp;{{ comment.create_date }}</p>
                </div>
            </li>
            <div class="comment-body">{{ comment.content_to_markdown|safe }}</div>
        </div>
        {% get_child_comments comment as child_comments %}
        {% if child_comments %}
        <ul class="list-unstyled ml-4">
            {% for each in child_comments %}
            <div class="comment-child pt-2" id="com-{{ each.id }}" >
                <li class="media">
                    {% if each.author.socialaccount_set.exists and each.author.avatar.url == '/media/avatar/default.png' %}
            <img class="avatar" src="{{ each.author.socialaccount_set.all.0.get_avatar_url }}" alt="{{ each.author }}">
            {% else %}
            <img class="avatar" src="{{ each.author.avatar.url }}" alt="{{ each.author }}">
            {% endif %}
                    <div class="media-body ml-2">
                        {% recall_com each as recall_check %}
                        {% if recall_check and user == each.author %}
                        <button type="button" class="del-message mr-2 float-right" data-csrf="{{ csrf_token }}"
                        data-ajax-url="{% url 'comment:del_comment' %}" data-mes-id="{{ each.id }}" data-article-id="{{ article.id }}">撤回</button>
                        {% endif %}
                        <a class="mr-2 rep-btn float-right"  href="#message-meditor"
                           data-repid="{{ each.id }}" data-repuser="{{ each.author.username }}">回复</a>
                        <p class="mt-0 mb-1"><strong>{{ each.author }}</strong>
                            {% if each.author.is_superuser %}
                            <small class="text-danger">[博主]</small>
                            {% endif %}
                            <i class="fa fa-share"></i>
                            @{{ each.rep_to.author.username }}
                        </p>
                        <p class="small text-muted">{{ each.create_date }}</p>
                    </div>
                </li>
                <div class="comment-body">{{ each.content_to_markdown|safe }}</div>
            </div>
            {% endfor %}
        </ul>
        {% endif %}
        {% empty %}
        暂时没有评论,欢迎来尬聊!
        {% endfor %}
    </ul>
</div>

在文章界面templates\blog\article.html中加入{% include 'comment/comment_list.html' %}即可调用评论区,调用{% include 'comment/message_form.html' %}调用评论编辑框。

评论/留言增加和删除的逻辑

因为在请求时,文章评论的增加和删除和留言信息的增加和删除,只是涉及到一个区别就是,前端传过来的数据是否有article_id,所以我们将两个两类不同的model集合到一个接口api中还是比较方便的。 apps\comment\views.py

from django.shortcuts import render
from apps.blog.models import Article
from .models import ArticleComment
from django.conf import settings
from django.http import JsonResponse
from django.views.decorators.http import require_POST
from django.contrib.auth.decorators import login_required
from datetime import datetime
from django.shortcuts import get_object_or_404
from django.db.models.signals import post_save
from django.views import generic
@login_required
@require_POST
def AddcommentView(request):
    if not request.is_ajax():return JsonResponse({'msg': '评论失败!'})
    data = request.POST
    user = request.user
    new_content = data.get('content', None)
    rep_id = data.get('rep_id', None)
    article_id = data.get('article_id', None)
    new_rep_to = (ArticleComment.objects.get(id=rep_id) if rep_id!='' else None) if article_id!='' else (Message.objects.get(id=rep_id) if rep_id!='' else None)
    # 评论/留言的层级
    try:
        new_parent = new_rep_to.parent if new_rep_to.parent else new_rep_to
    except AttributeError:
        new_parent = None
    # 文章评论或者为留言板留言
    new_message = (ArticleComment(author=user, content=new_content, belong=Article.objects.get(id=article_id), parent=new_parent, rep_to=new_rep_to)) if article_id!='' else (Message(author=user, content=new_content, parent=new_parent, rep_to=new_rep_to))
    new_message.save()

    new_point = '#mes-' + str(new_message.id)
    return JsonResponse({'msg': '评论提交成功!', 'new_point': new_point})

@login_required
@require_POST
def DelcommentView(request):
    if not request.is_ajax():return JsonResponse({'msg': '评论失败!'})
    data = request.POST
    user = request.user
    mes_id = data.get('mes_id', None)
    article_id = data.get('article_id', None)
    message = get_object_or_404(ArticleComment, author=user, belong=Article.objects.get(id=article_id), pk=mes_id) if article_id!=None else get_object_or_404(Message, author=user, pk=mes_id)
    message.delete()
    return JsonResponse({'msg': 'delete success'})

原创文章,转载请注明出处:https://boywithacoin.cn/article/li-yong-medeitorpei-zhi-ping-lun-gong-neng-liu-yan-mo-kuai/


您尚未登录,请 登录注册 后评论
    1 人参与 | 1 条评论
  • root
    回复

    root [博主]

    1楼 - 2020年6月4日 17:40

  • 尬聊