第二十一 BBS(2)

 对评论内容进行评论

1.1.增加评论按钮

comment_hander.py

def render_tree_node(tree_dic,margin_val):
    html = ""
    #展示子集评论
    for k, v in tree_dic.items():
        #合成评论、日期、用户名及评论按钮
        ele = "<div class='comment-node' style='margin-left:%spx'>" % margin_val + k.comment + "<span style='margin-left:20px'>%s</span>" %k.date \
              + "<span style='margin-left:20px'>%s</span>" %k.user.name \
              + '<span comment-id="%s"' %k.id +' style="margin-left:10px" class="glyphicon glyphicon-comment add-comment" aria-hidden="true"></span>' \
              + "</div>"
        html += ele
        html += render_tree_node(v,margin_val+10)
    return html

def render_comment_tree(tree_dic):
    #展示父级评论
    html = ""
    for k,v in tree_dic.items():
        ele = "<div class='root-comment'>" + k.comment + "<span style='margin-left:20px'>%s</span>" %k.date \
              + "<span style='margin-left:20px'>%s</span>" %k.user.name \
              + '<span comment-id="%s"' %k.id + 'style="margin-left:10px" class="glyphicon glyphicon-comment add-comment" aria-hidden="true"></span>' \
              + "</div>"
        html += ele
        html += render_tree_node(v,10)
    return html

查看效果:

1.2.点击评论按钮,展示评论框

1.2.1.克隆原来评论框

article_detail.html

 {% if request.user.is_authenticated %}
                <!-- 判断用户已经登录,输入框输入评论 -->
                <div class="new-comment-box"> <!-- 评论框增加样式 -->
                    <textarea class="form-control" rows="3"></textarea>
                    <!-- 按钮样式 -->
                    <button type="button" style="margin-top: 10px;" class="btn btn-success pull-right">评论</button>
                </div>
            {% else %}
                <div class="jumbotron">
                 <!-- 点击登录后,跳转到原先准备评论的页面,也就是给原路径加next?xxx -->
                  <h4 class="text-center"><a class="btn-link" href="{% url 'login' %}?next={{ request.path }}">登录</a>后评论</h4>
                </div>
            {% endif %}
<script>
    //评论展示
    function getComments() {
        $.get("{% url 'get_comments' article_obj.id %}",function(callback){
            //console.log(callback);
            $(".comment-list").html(callback);

            //start add comment
            $(".add-comment").click(function () {
                var comment_id = $(this).attr("comment-id");
                console.log("comment id" + comment_id);
                //克隆评论框并添加
                var new_comment_box_div = $(".new-comment-box").clone();
                $(".new-comment-box").remove();//删除之前的评论框,不删除会展示所有评论框
                $(this).parent().append(new_comment_box_div);
            })
        });
    }    

1.2.2.查看效果

1.3.新加评论内容并加到底部

1.3.1.评论新增

article_detail.html

<script>
    //评论展示
    function getComments() {
        $.get("{% url 'get_comments' article_obj.id %}",function(callback){
            //console.log(callback);
            $(".comment-list").html(callback);

            //start add comment
            $(".add-comment").click(function () {
                var comment_id = $(this).attr("comment-id");
                console.log("comment id" + comment_id);
                //克隆评论框并添加
                var new_comment_box_div = $(".new-comment-box").clone(true);
                $(".new-comment-box").remove();//删除之前的评论框,不删除会展示所有评论框
                $(this).parent().append(new_comment_box_div);
            })
        });
    }    
       $(".comment-box button").click(function () {
           var comment_text = $(".comment-box textarea").val()
           if (comment_text.trim().length < 5){
               alert("评论字数不能少于5");
           }else{
               //post
               //添加评论id
               var parent_comment_id = $(this).parent().prev().attr('comment-id');

               $.post("{% url 'post_comment' %}",
                   {
                       //1为评论
                       'comment_type':1,
                       article_id:"{{ article_obj.id }}",
                       parent_comment_id:parent_comment_id,
                       //评论内容
                       'comment':comment_text.trim(),
                       //获取csrf
                       'csrfmiddlewaretoken':getCsrf()
                   },
                   function(callback){
                       console.log(callback);
                       if (callback == "success"){
                           var new_comment_box_div = $(".new-comment-box").clone(true);
                           //在刷新评论之前,把评论框再放回文章底部
                           $(".comment-list").before(new_comment_box_div);
                           $(".new-comment-box textarea").val("");
                           //alert("hahhahahahha")
                           getComments();
                       }
               })//end post
           }//end if
       });//end button click

1.3.2.新增评论

 

 

 2.配置发帖

2.1.主页新增发帖选项

base.html

       <ul class="nav navbar-nav navbar-right">
              <!-- 如果用户登录,则显示用户名及注销,否则显示登录 -->
              {% if request.user.is_authenticated %}
                  <li class=""><a href="#">{{ request.user.userprofile.name }}</a></li>
                  <li class=""><a href="{% url 'logout' %}">注销</a></li>
              {% else %}
                  <li class=""><a href="{% url 'login' %}">登录/注册</a></li>
              {% endif %}
              <li class=""><a href="{% url 'new-article' %}">发帖</a></li>
          </ul>

2.2.配置url

from django.conf.urls import url,include
from bbs import views
urlpatterns = [
    url(r'^$', views.index),
    url(r'category/(\d+)/$', views.category),
    url(r'detail/(\d+)/$', views.article_detail,name="article_detail"),
    url(r'comment/$', views.comment,name="post_comment"),
    url(r'^comment_list/(\d+)/$', views.get_comments,name="get_comments"),
    url(r'^new_article/$', views.new_article,name="new-article"),
]

2.3.配置方法

2.3.1.配置modelForm

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.forms import ModelForm
from bbs import models

class ArticleModelForm(ModelForm):
    class Meta:
        model = models.Article
        exclude = ()

2.3.2.配置views

view.py


from bbs import form
def new_article(request):
    if request.method == 'GET':
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})

2.4.配置静态返回页面

{% extends 'base.html' %}
{% load custom %}
{% block page-container %}
    <div class="wrap-left">
        <form>
            {{ article_form }}
        </form>
    </div>
    <div class="wrap-right">
        right
    </div>
    <div class="clear-both"></div>
{% endblock %}

2.5.查看结果

 

2.6.配置编辑页面

2.6.1.下载文件

https://docs.ckeditor.com/ckeditor4/latest/guide/dev_installation.html#download

2.6.2.配置引用

 添加文件目录

配置文件引用

{% extends 'base.html' %}
{% load custom %}
{% block page-container %}
    <div class="wrap-left">
        <form>
            <textarea name="ckl" id="article-fatie"></textarea>
            {{ article_form }}
        </form>
    </div>
    <div class="wrap-right">
        right
    </div>
    <div class="clear-both"></div>
{% endblock %}
{% block bottom-js %}
    <script src="/static/plugins/ckeditor/ckeditor.js"></script>
    <script>
            CKEDITOR.replace('article-fatie');
    </script>
{% endblock %}

查看效果:

2.7.美化form表单

2.7.1.配置列表排列方式

拷贝之前的代码 form.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.forms import ModelForm
from bbs import models

class ArticleModelForm(ModelForm):
    class Meta:
        model = models.Article
        exclude = ()

    def __init__(self, *args, **kwargs):
        super(ArticleModelForm, self).__init__(*args, **kwargs)
        # self.fields['qq'].widget.attrs["class"] = "form-control"

        for filed_name in self.base_fields:
            filed = self.base_fields[filed_name]
            filed.widget.attrs.update({'class': 'form-control'})

查看效果:

 2.7.2.过滤掉不需要的选项

form.py

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from django.forms import ModelForm
from bbs import models

class ArticleModelForm(ModelForm):
    class Meta:
        model = models.Article
        exclude = ('author','pub_date','priority')

    def __init__(self, *args, **kwargs):
        super(ArticleModelForm, self).__init__(*args, **kwargs)
        # self.fields['qq'].widget.attrs["class"] = "form-control"

        for filed_name in self.base_fields:
            filed = self.base_fields[filed_name]
            filed.widget.attrs.update({'class': 'form-control'})

2.7.3.引用替换原有的textarea

{% extends 'base.html' %}
{% load custom %}
{% block page-container %}
    <div class="wrap-left">
        <form>
            {{ article_form }}
        </form>
    </div>
    <div class="wrap-right">
        right
    </div>
    <div class="clear-both"></div>
{% endblock %}
{% block bottom-js %}
    <script src="/static/plugins/ckeditor/ckeditor.js"></script>
    <script>
            CKEDITOR.replace('id_content');
    </script>
{% endblock %}

查看效果:

 2.8.发布文章

2.8.1.配置views.py

def new_article(request):
    if request.method == 'GET':
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})
    elif request.method == 'POST':
        print(request.POST)
        article_form = form.ArticleModelForm(request.POST)
        if article_form.is_valid():
            article_form.save()
        return HttpResponse('new article has been published!')

2.8.2.配置发布按钮

new_article.html

....
        <form>
            {{ article_form }}
            <input type="submit" class="btn btn-success pull-right" value="发布"/>
        </form>
....

2.8.3.发布文章测试

2.8.4.报错

2.8.5.新增CSRF

new_article.html

    <div class="wrap-left">
        <form method="post">{% csrf_token %}
            {{ article_form }}
            <input type="submit" class="btn btn-success pull-right" value="发布"/>
        </form>
    </div>

提交报错:

2.8.6.增加post方法

def new_article(request):
    if request.method == 'GET':
        print("this is get")
        print(request.method)
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})
    elif request.method == 'POST':
        print(request.POST)
        article_form = form.ArticleModelForm(request.POST)
        if article_form.is_valid():
            article_form.save()
            return HttpResponse('new article has been published!')
        else:
            return render(request,'bbs/new_article.html',{'article_form':article_form})

再次提交:

2.8.7.文件已经选择,仍然报错

 django 上传文件需要加字段

def new_article(request):
    if request.method == 'GET':
        print("this is get")
        print(request.method)
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})
    elif request.method == 'POST':
        print(request.POST)
        article_form = form.ArticleModelForm(request.POST,request.FILES)
        if article_form.is_valid():
            article_form.save()
            return HttpResponse('new article has been published!')
        else:
            return render(request,'bbs/new_article.html',{'article_form':article_form})

再次提交:

仍然提示,未选择任何文件,解决如下:

修改new_article.html

    <div class="wrap-left">
        <form method="post" enctype="multipart/form-data">{% csrf_token %}
            {{ article_form }}
            <input type="submit" class="btn btn-success pull-right" value="发布"/>
        </form>

再次提交:

作者id不能为空

2.8.8.处理作者id

修改方法,插入作者id数据:

def new_article(request):
    if request.method == 'GET':
        print("this is get")
        print(request.method)
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})
    elif request.method == 'POST':
        print(request.POST)
        article_form = form.ArticleModelForm(request.POST,request.FILES)
        if article_form.is_valid():
            #获取数据
            data = article_form.cleaned_data
            data['author_id'] = request.user.userprofile.id
            article_obj = models.Article(**data)
            article_obj.save()
            #article_form.save()
            return HttpResponse('new article has been published!')
        else:
            return render(request,'bbs/new_article.html',{'article_form':article_form})

提交内容:

发布成功:

查看页面:

页面却是html元素格式:

修改如下:

article_detail.html

        <div class="article-content">
            <img class="article-detail-head-img" src="/static/{{ article_obj.head_img|truncate_url }}">
            <!-- 文章内容 -->
            {{ article_obj.content|safe }}
        </div>

再次查看

页面排序,按最新发布排序,修改index.html:

....
     {% for article in article_list reversed %}
            <div class="article-box row">
                <!-- 展示文章图片 -->
....

 

 

 

 2.8.9.在用户不登录的情况下发帖

报错如下:

匿名用户没有相关属性,用户必须登录验证

2.8.10.增加用户验证

在settings里增加login url:

STATIC_URL = '/static/'

STATICFILES_DIRS = [
    os.path.join(BASE_DIR, "statics"),
    os.path.join(BASE_DIR, "uploads")
    # '/var/www/static/',
]

LOGIN_URL ='/login/'

增加验证:

@login_required()
def new_article(request):
    if request.method == 'GET':
        print("this is get")
        print(request.method)
        article_form = form.ArticleModelForm()
        return render(request,'bbs/new_article.html',{'article_form':article_form})
    elif request.method == 'POST':
        print(request.POST)
        article_form = form.ArticleModelForm(request.POST,request.FILES)
        if article_form.is_valid():
            #获取数据
            data = article_form.cleaned_data
            data['author_id'] = request.user.userprofile.id
            article_obj = models.Article(**data)
            article_obj.save()
            #article_form.save()
            return HttpResponse('new article has been published!')
        else:
            return render(request,'bbs/new_article.html',{'article_form':article_form})

未登录发帖:

跳转到登录:

 2.9.单独文件上传

2.9.1.新增文件上传

修改new_article.html

    <div class="wrap-left">
        <form method="post" enctype="multipart/form-data">{% csrf_token %}
            {{ article_form }}
            <input type="submit" class="btn btn-success pull-right" value="发布"/>
        </form>

        <hr/>
        <!-- 单独上传文件 -->
        <form method="post"  enctype="multipart/form-data" action="{% url 'file-upload' %}">
            <input name="filename" type="file">{% csrf_token %}
            <input type="submit" value="上传">
        </form>
    </div>

2.9.2.配置views.py

...
def file_upload(request):
    print(request.FILES)
    return render(request,'bbs/new_article.html')

2.9.3.配置url

新增file_upload

from django.conf.urls import url,include
from bbs import views
urlpatterns = [
    url(r'^$', views.index),
    url(r'category/(\d+)/$', views.category),
    url(r'detail/(\d+)/$', views.article_detail,name="article_detail"),
    url(r'comment/$', views.comment,name="post_comment"),
    url(r'^comment_list/(\d+)/$', views.get_comments,name="get_comments"),
    url(r'^new_article/$', views.new_article,name="new-article"),
    url(r'file_upload/$', views.file_upload,name="file-upload"),
]

2.9.4.测试文件上传

获取到文件名:

 说明:文件小于2.5M直接传入到内存,再写入磁盘,如果文件大于2.5M,则先写入临时文件,再加载到本地磁盘

测试上传一个大文件,结果:

 2.9.5.修改上传方法

def file_upload(request):
    file_obj = request.FILES.get('filename')
    print(file_obj.name)
    with open('uploads/%s' % file_obj.name, 'wb+') as destination:
        for chunk in file_obj.chunks():
            destination.write(chunk)
    return render(request,'bbs/new_article.html')
2.9.5.1.上传文件测试:

查看结果:

 

2.9.5.2.上传大文件

上传进度:

查看结果:

 3.新消息提醒添加

3.1.添加静态方法

思路:通过文章id来获取最后一篇文章的id值,每隔3秒检查,当目前id大于最后id则认为是新消息

修改index.html

3.1.1添加id

            <div article_id="{{ article.id }}" class="article-box row">

3.1.2.添加js

{% block bottom-js %}
    <script>
        $(document).ready(function () {
           var new_article_refresh = setInterval(function () {
               var latest_article_id = $(".wrap-left").children(":first").attr("article_id");
               $.getJSON("{% url 'get_latest_article_count' %}",{latest_id:latest_article_id},function(callback){
                    console.log(callback);
               });// end get
               console.log(latest_article_id);
           },3000) //end interval
        }); //end document
    </script>
{% endblock %}

3.2.添加url

from django.conf.urls import url,include
from bbs import views
urlpatterns = [
    url(r'^$', views.index),
    url(r'category/(\d+)/$', views.category),
    url(r'detail/(\d+)/$', views.article_detail,name="article_detail"),
    url(r'comment/$', views.comment,name="post_comment"),
    url(r'^comment_list/(\d+)/$', views.get_comments,name="get_comments"),
    url(r'^new_article/$', views.new_article,name="new-article"),
    url(r'file_upload/$', views.file_upload,name="file-upload"),
    url(r'^latest_article_count/$', views.get_latest_article_count,name="get_latest_article_count"),
]

3.3.添加views方法

def get_latest_article_count(request):
    latest_article_id = request.GET.get("latest_id")
    new_article_count = models.Article.objects.filter(id__gt = latest_article_id).count()
    print("new_article_count",new_article_count)
    return HttpResponse(json.dumps({'new_article_count':new_article_count}))

3.4.查看获取

3.4.1.获取文章id及当前新文章

3.4.2.新增一篇文章

新增文章变成1:

 3.5.新消息显示

3.5.1.新增静态显示index.html

        <div class="new-article-notify hide"><span></span>条新文章
        </div>
 <script>
        $(document).ready(function () {
           var new_article_refresh = setInterval(function () {
               var latest_article_id = $(".wrap-left").children(":first").attr("article_id");
               $.getJSON("{% url 'get_latest_article_count' %}",{latest_id:latest_article_id},function(callback){
                    console.log(callback);

                    if (callback.new_article_count > 0){
                        $(".new-article-notify").toggle("hide");
                        $(".new-article-notify span").html(callback.new_article_count);
                    }
               });// end get
               console.log(latest_article_id);
           },3000) //end interval
        }); //end document
    </script>

3.5.2.运行报错

解决:

def get_latest_article_count(request):
    latest_article_id = request.GET.get("latest_id")
    if latest_article_id:
        new_article_count = models.Article.objects.filter(id__gt = latest_article_id).count()
        print("new_article_count",new_article_count)
    else:
        latest_article_id = 0
        new_article_count = models.Article.objects.filter(id__gt=latest_article_id).count()
    return HttpResponse(json.dumps({'new_article_count':new_article_count}))

结果:

3.6.新消息显示问题

3.6.1.修改最新id

最新id:

3.6.2.修改为8

仍然没有消息显示,获取最新的id错误,修改如下:

<script>
        $(document).ready(function () {
           var new_article_refresh = setInterval(function () {
               //获取第一个值
               var latest_article_id = $(".wrap-left").children()[1].attr("article_id");
               $.getJSON("{% url 'get_latest_article_count' %}",{latest_id:latest_article_id},function(callback){
                    console.log(callback);

                    if (callback.new_article_count > 0){
                        $(".new-article-notify").toggle("hide");
                        $(".new-article-notify span").html(callback.new_article_count);
                    }
               });// end get
               console.log(latest_article_id);
           },3000) //end interval
        }); //end document
    </script>

报错:

解决:

//如果外面不加$(),那么返回的是一个html元素,而不是一个对象,没有attr属性
var latest_article_id = $($(".wrap-left").children()[1]).attr("article_id");

 结果:

 3.6.3.修改新消息显示

有新消息之后,将隐藏属性去掉:

  <script>
        $(document).ready(function () {
           var new_article_refresh = setInterval(function () {
               //获取第一个值
               var latest_article_id = $($(".wrap-left").children()[1]).attr("article_id");
               $.getJSON("{% url 'get_latest_article_count' %}",{latest_id:latest_article_id},function(callback){
                    console.log(callback);

                    if (callback.new_article_count > 0){
                        //$(".new-article-notify").toggle("hide");
                        if($(".new-article-notify").hasClass("hide")){
                            $(".new-article-notify").removeClass("hide");
                        }
                        $(".new-article-notify span").html(callback.new_article_count);
                    }
               });// end get
               console.log(latest_article_id);
           },3000) //end interval
        }); //end document
    </script>

修改属性:

查看结果:

3.6.4.为新消息增加样式

custom.css

.new-article-notify {
    background-color: #ff6f06;
    padding: 5px;
    text-align: center;
}

返回当前页面,刷新整个页面,比较粗糙:

        <div class="new-article-notify hide">
                <a href="{{ request.path }}"><span></span>条新文章</a>
        </div>

查看样式:

3.6.5.增加新文章

结果:

点击新消息:

 

posted @ 2018-03-05 11:41  ckl893  阅读(127)  评论(0编辑  收藏  举报