美文网首页
6.1 django项目-新闻博客系统之新闻详情页

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

作者: yungege | 来源:发表于2019-08-27 15:00 被阅读0次

    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('服务器超时,请重试!');
                })
    
        })
    
    
    });
    

    相关文章

      网友评论

          本文标题:6.1 django项目-新闻博客系统之新闻详情页

          本文链接:https://www.haomeiwen.com/subject/wkeeectx.html