目标效果:
image.png
html的表单变成django_form
image.png
在comment中创建forms.py文件,编写代码:

from django import forms
from django.contrib.contenttypes.models import ContentType
from django.db.models import ObjectDoesNotExist
from ckeditor.widgets import CKEditorWidget


class CommentForm(forms.Form):
    content_type = forms.CharField(widget=forms.HiddenInput)
    object_id = forms.IntegerField(widget=forms.HiddenInput)
    text = forms.CharField(widget=CKEditorWidget(config_name='comment_ckeditor'),
                           error_messages={'required': '评论内容不能为空'})


    def __init__(self, *args, **kwargs):
        if 'user' in kwargs:
            self.user = kwargs.pop('user')
        super(CommentForm, self).__init__(*args, **kwargs)


    def clean(self):
        # 判断用户是否登录
        if self.user.is_authenticated:
            self.cleaned_data['user'] = self.user
        else:
            raise forms.ValidationError('用户尚未登录')


        # 评论对象验证
        content_type = self.cleaned_data['content_type']
        object_id  =  self.cleaned_data['object_id']
        try:
            model_class = ContentType.objects.get(model=content_type).model_class()
            model_obj = model_class.objects.get(pk=object_id)
            self.cleaned_data['content_object'] = model_obj
        except ObjectDoesNotExist:  # 不使用exceptions的原因时为了防止将任何错误都归因于评论对象不存在从而导致难以维护
            raise forms.ValidationError('评论对象不存在')


        return self.cleaned_data

在comment中的views.py中导入Comment并且在下面将该参数传递给前端,

from django.shortcuts import render, redirect
from django.contrib.contenttypes.models import ContentType
from django.urls import reverse
from django.http import JsonResponse
from .models import Comment
from .forms import CommentForm


def update_comment(request):
    referer = request.META.get('HTTP_REFERER', reverse('home'))
    comment_form = CommentForm(request.POST, user=request.user)  # 实例化
    data = {}


    if comment_form.is_valid():
        # 检查通过,保存数据
        comment = Comment()
        comment.user = comment_form.cleaned_data['user']
        comment.text = comment_form.cleaned_data['text']
        comment.content_object = comment_form.cleaned_data['content_object']
        comment.save()


        # 返回数据
        data['status'] = 'SUCCESS'
        data['username'] = comment.user.username
        data['comment_time'] = comment.comment_time.strftime('%Y-%m-%d %H:%M:%S')
        data['text'] = comment.text
    else:
        #return render(request, 'error.html', {'message': comment_form.errors, 'redirect_to': referer})
        data['status'] = 'ERROR'
        data['message'] = list(comment_form.errors.values())[0][0]
    return JsonResponse(data)

然后再blog_detail中提价评论下面增加{{comment_form}}以加入渲染

<h3 class="comment-area-title">提交评论</h3>
{% if user.is_authenticated %}
    <form action="{% url 'update_comment' %}" method="POST" style="overflow:hidden">
        {% csrf_token %}
        {{ comment_form }}
        
        <div class="form-group">
            <label for="comment_text">{{ user.username }},欢迎评论~</label>

修改blog/views.py中blog_detail

from comment.forms import CommentForm
......
def blog_detail(request, blog_pk):
    context['comment_form'] = CommentForm(initial={'content_type': blog_content_type.model, 'object_id': blog_pk})

效果如下:
image.png
两个框,而且文本编辑功能欠缺,我们优化并增加一下新功能:

将blog\_detail.html中的欢迎评论周围简化样式,并且优化:

新的

{# 删除和base中重复的内容,留下独有的内容,然后分别填充到下面的两个block中 #}


{# 这是页面标题 #}
{% extends 'base.html' %}
{% block title %}{{ blog.title }}{% endblock %}{# 这里因为之前title被包起来了,所以直接用变量即可 #}
{% block nav_blog_active %}active{% endblock %}


{% load static %}
{% block header_extends %}
    <link rel="stylesheet" href="{% static 'blog/blog.css' %}">
    <script type="text/javascript" src="{% static "ckeditor/ckeditor-init.js" %}"></script>
    <script type="text/javascript" src="{% static "ckeditor/ckeditor/ckeditor.js" %}"></script>
{% endblock %}


{# 页面内容 #}
{% block content %}
    <div class="container">
        <div class="row">
            <div class="col-xs-10 col-xs-offset-1">
                <h3>{{ blog.title }}</h3>
                <ul class="blog-info-description">
                    <li>作者:{{ blog.author }}</li>
                    <li>分类:<a href="{% url 'blogs_with_type' blog.blog_type.pk %}">{{ blog.blog_type }}</a></li>
                    <li>发表日期:{{ blog.created_time|date:"Y-m-d H:i:s" }}</li>
                    <li>阅读量:({{ blog.get_read_num }})</li>
                </ul>              
                <div class="blog-content">{{ blog.content|safe }}</div>
                <div class="blog-more">
                    <p>上一篇:
                        {% if previous_blog %}
                            <a href="{% url 'blog_detail' previous_blog.pk %}">{{ previous_blog.title }}</a>
                        {% else %}
                            没有了
                        {% endif %}
                    </p>
                    <p>下一篇:
                        {% if next_blog %}
                            <a href="{% url 'blog_detail' next_blog.pk %}">{{ next_blog.title }}</a>
                        {% else %}
                            没有了
                        {% endif %}
                    </p>
                </div>
            </div>
        </div>
        <div class="row">
            <div class="col-xs-10 col-xs-offset-1">
                <div class="comment-area">
                    <h3 class="comment-area-title">提交评论</h3>
                    {% if user.is_authenticated %}
                        <form id="comment_form" action="{% url 'update_comment' %}" method="POST" style="overflow:hidden">
                            <label>{{ user.username }},欢迎评论~</label>
                            {% csrf_token %}                            
                            {% for field in comment_form %}
                                {{ field }}
                            {% endfor %}
                            <span id="comment_error" class="text-danger pull-left"></span>
                            <input type="submit" value="评论" class="btn btn-primary pull-right">
                        </form>
                    {% else %}
                        您尚未登录,登录之后方可评论~
                        <a class="btn btn-primary" href="{% url 'login' %}?from={{ request.get_full_path }}">登录</a>
                        <span> or </span>
                        <a class="btn btn-danger" href="{% url 'register' %}?from={{ request.get_full_path }}">注册</a>
                    {% endif %}
                </div>
                <div class="comment-area">
                    <h3 class="comment-area-title">评论列表</h3>
                    <div id="comment_list">
                        {% for comment in comments %}
                            <div>
                                {{ comment.user.username }}
                                ({{ comment.comment_time|date:"Y-m-d H:i:s" }}):
                                {{ comment.text|safe }}
                            </div>
                        {% empty %}
                            暂无评论
                        {% endfor %}
                    </div>                    
                </div>
            </div>
        </div>
    </div>    
{% endblock %}
    
{% block script_extends %}
    <script type="text/javascript">
        $("#comment_form").submit(function(){
            // 判断是否为空
            $("#comment_error").text('');
            if(CKEDITOR.instances["id_text"].document.getBody().getText().trim()==''){
                $("#comment_error").text('评论内容不能为空');
                return false;
            }


            // 更新数据到textarea
            CKEDITOR.instances['id_text'].updateElement();


            // 异步提交
            $.ajax({
                url: "{% url 'update_comment' %}",
                type: 'POST',
                data: $(this).serialize(),
                cache: false,
                success: function(data){
                    console.log(data);
                    if(data['status']=="SUCCESS"){
                        // 插入数据
                        var comment_html = '<div>' + data['username'] +
                                           ' (' + data['comment_time'] + '):' +
                                           data['text'] + '</div>';
                        $("#comment_list").prepend(comment_html);
                        // 清空编辑框的内容
                        CKEDITOR.instances['id_text'].setData('');
                    }else{
                        // 显示错误信息
                        $("#comment_error").text(data['message']);
                    }                    
                },
                error: function(xhr){
                    console.log(xhr);
                }
            });
            return false;
        });
    </script>
{% endblock %}

原来的:

        <div class="row">
            <div class="col-xs-10 col-xs-offset-1">
                <div class="comment-area">
                    <h3 class="comment-area-title">提交评论</h3>
                    {% if user.is_authenticated %}
                        <form action="{% url 'update_comment' %}" method="POST" style="overflow:hidden">
                            {% csrf_token %}
                            {{ comment_form }}


                            <div class="form-group">
                                <label for="comment_text">{{ user.username }},欢迎评论~</label>
                                <textarea id="comment_text" class="form-control" name="text" rows="4"></textarea>
{#使用input无法多行输入,换成textarea来写多行内容,使用bootstrap中的form-control对编辑区域和提交功能的性能优化#}
                            </div>


                            <input type="hidden" name="object_id" value="{{ blog.pk }}">
                            <input type="hidden" name="content_type" value="blog">
                            <input type="submit" value="评论" class="btn btn-primary" style="float:right">
                        </form>
                    {% else %}
                        您尚未登录,登录之后方可评论~
                        <a class="btn btn-primary" href="{% url 'login' %}?from={{ request.get_full_path }}">登录</a>
                        <span> or </span>
                        <a class="btn btn-danger" href="{% url 'register' %}?from={{ request.get_full_path }}">注册</a>
                    {% endif %}
                </div>
                <div class="comment-area">
                    <h3 class="comment-area-title">评论列表</h3>
                    {% for comment in comments %}
                        <div>
                            {{ comment.user.username }}
                            ({{ comment.comment_time|date:"Y-m-d H:n:s" }}):
                            {{ comment.text }}
                        </div>
                    {% empty %}
                        暂无评论
                    {% endfor %}
                </div>
            </div>
        </div>

在settings.中加入

CKEDITOR_CONFIGS = {
    'comment_ckeditor': {
        'toolbar': 'custom',
        'toolbar_custom': [
            ['Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript'],
            ["TextColor", "BGColor", 'RemoveFormat'],
            ['NumberedList', 'BulletedList'],
            ['Link', 'Unlink'],
            ["Smiley", "SpecialChar", 'Blockquote'],
        ],
        'width': 'auto',
        'height': '180',
        'tabSpaces': 4,
        'removePlugins': 'elementspath',
        'resize_enabled': False,
    }
}

然后增加blog.css样式

div.django-ckeditor-widget {
    width: 100%;
}

修改blog.forms.py中的CommentFomr类下面的text内容

text = forms.CharField(widget=CKEditorWidget(config_name='comment_ckeditor'),
                       error_messages={'required': '评论内容不能为空'})

给comment/models.py中增加袁磊,使其按照评论时间倒序排列:

    class Meta:
        ordering = ['-comment_time']

笨小孩
20 声望3 粉丝

你,要怎样度过这一生?有的人二十岁已经死了,有的人七十岁还在发现生命的可能,有人终其一生,不知道自己要的是什么;有人简单执拗,终其一生;忠于自我未必有结果,坚持努力也不一定换来成功,但有天,回望过...