6.1 django项目-新闻博客系统之新闻详情页

2019-08-27  本文已影响0人  yungege

06 新闻详情页

一、功能需求分析

1、功能

二、新闻详情页

1、接口设计

  1. 接口说明

    项目项目 说明说明
    请求方法 GET
    url /news/<int:news_id>/
    参数类型 查询参数
  2. 返回结果

    新闻详情html

2、后端代码

def news_detial(request, news_id):
    if News.objects.filter(id=news_id, is_delete=False).exists():
        return render(request, 'news/news_detail.html',context={'news_id': news_id})
    else:
        return HttpResponseNotFound('<h1>Page not found</h1>')

3、前端html

{% extends 'base/base.html' %}
{% load static %}

{% block title %}新闻详情{% endblock %}

{% block link %}
<link rel="stylesheet" href="{% static 'css/news/news-detail.css' %}">
{% endblock %}

{% block main_contain %}
      <div class="news-contain" news_id="{{ news_id }}">
      <h1 class="news-title"></h1>
      <div class="news-info">
        <div class="news-info-left">
          <span class="news-author">作者</span>
          <span class="news-pub-time">1小时前</span>
          <span class="news-type">类型</span>
        </div>
      </div>
      <article class="news-content">
        文章内容
      </article>
      <div class="comment-contain">
        <div class="comment-pub clearfix">
          <div class="new-comment">
            文章评论(<span class="comment-count">0</span>)
          </div>
                {% if user.is_authenticated %}

                <div class="comment-control logged-comment">
                    <input type="text" placeholder="请填写评论">
                </div>
                {% else %}
                <div class="comment-control please-login-comment">
                    <input type="text" placeholder="请登录后参加评论" readonly>
                </div>
                {% endif %}
                <button class="comment-btn">发表评论</button>
                {% csrf_token %}
        </div>
        <ul class="comment-list">

        </ul>
      </div>

    </div>
{% endblock %}

{% block otherjs %}
    <script src="{% static 'js/base/message.js' %}"></script>
    <script src="{% static 'js/news/detial.js' %}"></script>
{% endblock otherjs %}

三、新闻详情

1、接口设计

  1. 接口说明

    项目项目 说明说明
    请求方法 GET
    url /news/detiallist/
    参数类型 查询参数
  2. 参数说明

    参数名 类型 是否必须 描述
    news_id 整型 新闻id
  3. 返回结果

    {
        "error": "0",
        "errmsg": "",
        "data": {
            'news_id': news_id,
            'news':{
                'title': title,
                'content': content,
                'update_time': update_time,
                'tag_name': tag_name,
                'author_username': author_username
                }
        }
    }
    

2、后端代码

def news_detial_list(request):
    try:
        news_id = int(request.GET.get('news_id', 1))
    except Exception as e:
        logger.error('新闻id错误:\n{}'.format(e))
        news_id = 1

    news = News.objects.values('title', 'content', 'update_time').annotate(
        tag_name=F('tag__name'),
        author_username=F('author__username')).filter(id=news_id, is_delete=False)

    news_list = list(news)

    if news_list:
        data = {
            'news_id': news_id,
            'news': news_list
        }

        return json_response(data=data)
    else:
        return json_response(errno=Code.PARAMERR, errmsg=error_map[Code.PARAMERR])

路由

path('news/detiallist/', views.news_detial_list, name='detial_list'),

四、评论

1、模型设计

class Comments(BaseModel):
    """
    评论模型
    """
    content = models.TextField('内容', help_text='内容')
    author = models.ForeignKey('user.User', on_delete=models.SET_NULL, null=True)
    news = models.ForeignKey('News', on_delete=models.CASCADE)

    # 本项目设计二级评论,修改Comments模型,添加一个parent字段
    parent = models.ForeignKey('self', on_delete=models.CASCADE, null=True)

    class Meta:
        ordering = ['-update_time', '-id']  # 排序
        db_table = "tb_comments"  # 指明数据库表名
        verbose_name = "评论"  # 在admin站点中显示的名称
        verbose_name_plural = verbose_name  # 显示的复数名称

    def to_dict_data(self):
        comment_dict = {
            'news_id': self.news_id,
            'content_id': self.id,
            'content': self.content,
            'author': self.author.username,
            'update_time': self.update_time.astimezone().strftime('%Y年%m月%d日 %H:%M'),
            'parent': self.parent.to_dict_data() if self.parent else None
        }
        return comment_dict

2、接口设计

  1. 接口说明

    项目项目 说明说明
    请求方法 GET
    url /news/comments/
    参数类型 查询参数
  2. 参数说明

    参数名 类型 是否必须 描述
    news_id 整型 新闻id
  3. 返回结果

    {
        "error": "0",
        "errmsg": "",
        "data": {
            'news_id': news_id,
            'comments':{
                'id': id,
                'content': content,
                'update_time': update_time,
                'author_username': author_username,
                'parent_author_username': parent_author_username,
                'parent_content': parent_content,
                'parent_update_time': parent_update_time,
                }
        }
    }
    

3、后端代码

def comment_list(request):
    try:
        news_id = int(request.GET.get('news_id', 1))
    except Exception as e:
        logger.error('新闻id错误:\n{}'.format(e))
        news_id = 1

    comments = Comments.objects.values('id',
                'content', 'update_time',).annotate(
        author_username=F('author__username'),
        parent_author_username=F('parent__author__username'),
        parent_content=F('parent__content'),
        parent_update_time=F('parent__update_time'),
    ).filter(news_id=news_id, is_delete=False)

    # print(list(comments))

    data = {
        'news_id': news_id,
        'comments': list(comments)
    }

    return json_response(data=data)

路由

path('news/comments/', views.comment_list, name='comments_list'),

导入数据

五、添加评论

1、接口设计

1、接口说明

项目项目 说明说明
请求方法 POST
url /news/<int:news_id>/addcomments/
参数类型 查询参数

2、参数说明

参数名 类型 是否必须 描述
news_id 整数 新闻id
content 字符串 新闻评论内容
parent_id 整数 父评论id

注意:post请求需要携带csrftoken

  1. 返回结果

    {
        "error": "0",
        "errmsg": "",
        "data": {
             'news_id': news_id,
                'content_id': id,
                'content': content,
                'author': author,
                'update_time': update_time
             'parent': {
                    'news_id': news_id,
                    'content_id': id,
                    'content': content,
                    'author': author,
                    'update_time': update_time
                    'parent': null
            }
        }
    }
    
参数名 类型 是否必须 描述
news_id 整数 新闻id
content 字符串 新闻评论内容
parent_id 整数 父评论id

注意:post请求需要携带csrftoken

参数名 类型 是否必须 描述
news_id 整数 新闻id
content 字符串 新闻评论内容
parent_id 整数 父评论id

注意:post请求需要携带csrftoken

参数名 类型 是否必须 描述
news_id 整数 新闻id
content 字符串 新闻评论内容
parent_id 整数 父评论id

注意:post请求需要携带csrftoken

2、后端代码

def add_comment(request,news_id):
    if request.method == 'POST':
        # 是否登录
        if not request.user.is_authenticated:
            return json_response(errno=Code.SESSIONERR, errmsg=error_map[Code.SESSIONERR])
        form = Checkaddcomments(request.POST)
        if form.is_valid():
            # 校验成功
            # 将评论写入数据库
            # 保存到数据库
            news_id = form.cleaned_data.get('news_id')
            content = form.cleaned_data.get('content')
            parent_id = form.cleaned_data.get('parent_id')
            new_comment = Comments()
            new_comment.content = content
            new_comment.news_id = news_id
            new_comment.author = request.user
            new_comment.parent_id = parent_id if parent_id else None
            new_comment.save()

            return json_response(data=new_comment.to_dict_data())
        else:
            err_msg_str = form.get_errors()
            return json_response(errno=Code.PARAMERR, errmsg=err_msg_str)

路由

path('news/<int:news_id>/addcomments/', views.add_comment, name='addcomments'),

六、前端设计

1、前端js

/*=== newsdetialStart ===*/
$(function () {
    fn_load_newsdetial();
    console.log($('.news-contain').attr('news_id'));
    function fn_load_newsdetial() {
        let $news_id = $('.news-contain').attr('news_id');
        $
            .ajax({
                url:'/news/detiallist/?news_id=' + $news_id,
                type:'GET',
                dataType:'json'
            })
            .done((resp)=>{
                if(resp.errno === '0')
                {
                    let $news = resp.data.news[0];
                    $('.news-title').html($news.title);
                    $('.news-author').html($news.author_username);
                    $('.news-pub-time').html($news.update_time);
                    $('.news-type').html($news.tag_name);
                    $('.news-content').html($news.content);

                }
                else
                {
                    message.showError(resp.errmsg)
                }
            })
            .fail(()=>{
                message.showError('服务器超时,请重试!')
            })
    }
});
/*=== newsdetialEnd ===*/

/*=== commentsStart ===*/
$(function () {
    fn_load_comments();
    function fn_load_comments() {
        let $news_id = $('.news-contain').attr('news_id');
        $
            .ajax({
                url:'/news/comments/?news_id=' + $news_id,
                type:'GET',
                dataType:'json'
            })
            .done((resp)=>{
                if(resp.errno === '0')
                {
                    // message.showSuccess('评论获取成功');
                    resp.data.comments.forEach(function (comment) {
                        let $parent=``;
                        if(comment.parent_author_username)
                        {
                            $parent = `<div class="parent_comment_text">
                                <div class="parent_username">${comment.parent_author_username}</div>
                                <div class="comment_time">${comment.parent_update_time}</div>

                                <div class="parent_content_text">
                                    ${comment.parent_content}
                                </div>

                            </div>`;
                        }
                    let content = `<li class="comment-item">
                        <div class="comment-info clearfix">
                            <img src="/static/images/avatar.jpeg" alt="avatar" class="comment-avatar">
                            <span class="comment-user">${comment.author_username}</span>
                            <span class="comment-pub-time">${comment.update_time}</span>
                        </div>
                        <div class="comment-content">${comment.content}</div>`
                        + $parent +
                        `<a href="javascript:void(0);" class="reply_a_tag right_float">回复</a>
                        <form class="reply_form left_float" comment-id="${comment.id}"
                              news-id="${resp.data.news_id}">
                            <textarea class="reply_input"></textarea>
                            <input type="button" value="回复" class="reply_btn right_float">
                            <input type="reset" name="" value="取消" class="reply_cancel right_float">
                        </form>

                    </li>`;
                    $('.comment-list').append(content);
                    })

                }
                else
                {
                    message.showError(resp.errmsg)
                }
            })
            .fail(()=>{
                message.showError('服务器超时,请重试!')
            })
    }
});



// 修改static/js/news/news_detail.js中的代码如下
// 修改static/js/news/news_detail.js中的代码如下
$(function () {
    // 对评论进行评论
    $('.comment-list').delegate('a,input', 'click', function () {
        //获取回复按钮的class属性
        let sClassValue = $(this).prop('class');
        // 如果点击的是回复按钮,就显示输入框
        if (sClassValue.indexOf('reply_a_tag') >= 0) {
            $(this).next().toggle();
        }
        // 如果点击的是取消按钮,就隐藏输入框
        if (sClassValue.indexOf('reply_cancel') >= 0) {
            $(this).parent().toggle();
        }

        if (sClassValue.indexOf('reply_btn') >= 0) {
            // 评论
            let $this = $(this);
            let parent_id = $this.parent().attr('comment-id');
            let content = $this.prev().val();
            let news_id = $('.news-contain').attr('news_id');
            if (!content) {
                message.showError('请输入评论内容!');
                return
            }
            $
                .ajax({
                    url: '/news/' + news_id + '/addcomments/',
                    type: 'POST',
                    data: {
                        news_id:news_id,
                        content: content,
                        parent_id: parent_id
                    },
                    dataType: "json"
                })

                .done((res) => {
                    if (res.errno === '0') {
                        let comment = res.data;
                        let html_comment = `<li class="comment-item">
            <div class="comment-info clearfix">
              <img src="/static/images/avatar.jpeg" alt="avatar" class="comment-avatar">
              <span class="comment-user">${comment.author}</span>
            </div>
            <div class="comment-content">${comment.content}</div>

                <div class="parent_comment_text">
                  <div class="parent_username">${comment.parent.author}</div>
                  <div class="comment_time">${comment.parent.update_time}</div>
                  <div class="parent_content_text">
                    ${comment.parent.content}
                  </div>
                </div>

              <div class="comment_time left_float">${comment.update_time}</div>
              <a href="javascript:;" class="reply_a_tag right_float">回复</a>
              <form class="reply_form left_float" comment-id="${comment.content_id}" news-id="${comment.news_id}">
                <textarea class="reply_input"></textarea>
                <input type="button" value="回复" class="reply_btn right_float">
                <input type="reset" name="" value="取消" class="reply_cancel right_float">
              </form>

          </li>`;
                        message.showSuccess('评论成功!');
                        setTimeout(() => {
                            $('.comment-list').prepend(html_comment);
                        }, 800);

                        $this.prev().val('');   // 清空输入框
                        $this.parent().hide();  // 关闭评论框
                    } else if (res.errno === '4101') {
                        // 用户未登录
                        message.showError(res.errmsg);
                        setTimeout(() => {
                            window.location.href = '/login/'
                        }, 800)
                    } else {
                        // 失败
                        message.showError(res.errmsg)
                    }
                })
                .fail(() => {
                    message.showError('服务器超时,请重试')
                })
        }
    });

    // 对新闻评论
    let $newsComment = $('.logged-comment input');            // 新闻评论框
    let $sendComment = $('.comment-pub .comment-btn');           // 新闻评论按钮

    $sendComment.click(function () {

        let $this = $(this);
        if ($this.prev().hasClass('please-login-comment')) {
            message.showError('未登录,请登录后再评论!');
            setTimeout(() => {
                window.location.href = '/login/'
            }, 800);
            return
        }
        let news_id = $('.news-contain').attr('news_id');
        let content = $newsComment.val();
        if (!content) {
            message.showError('请输入评论内容!');
            return
        }
        $
            .ajax({
                url: '/news/' + news_id + '/addcomments/',
                type: 'POST',
                data: {
                    news_id:news_id,
                    content: content
                },
                dataType: 'json'
            })
            .done((res) => {
                if (res.errno === '0') {
                    let comment = res.data;
                    let html_comment = `<li class="comment-item">
            <div class="comment-info clearfix">
              <img src="/static/images/avatar.jpeg" alt="avatar" class="comment-avatar">
              <span class="comment-user">${comment.author}</span>
              <span class="comment-pub-time">${ comment.update_time }</span>
            </div>
            <div class="comment-content">${comment.content}</div>

              <a href="javascript:;" class="reply_a_tag right_float">回复</a>
              <form class="reply_form left_float" comment-id="${comment.content_id}" news-id="${comment.news_id}">
                <textarea class="reply_input"></textarea>
                <input type="button" value="回复" class="reply_btn right_float">
                <input type="reset" name="" value="取消" class="reply_cancel right_float">
              </form>

          </li>`;
                    message.showSuccess('评论成功!');
                    setTimeout(() => {
                        $(".comment-list").prepend(html_comment);
                    }, 800);

                    // 清空
                    $newsComment.val('');

                } else if (res.errno === '4101') {
                    // 用户未登录
                    message.showError(res.errmsg);
                    setTimeout(() => {
                        window.location.href = '/user/login/'
                    }, 800)

                } else {
                    message.showError(res.errmsg);
                }
            })

            .fail(() => {
                message.showError('服务器超时,请重试!');
            })

    })


});
上一篇下一篇

猜你喜欢

热点阅读