(二十)首页内容详细详细页+ 评论 + 回复

Posted a438842265

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了(二十)首页内容详细详细页+ 评论 + 回复相关的知识,希望对你有一定的参考价值。

1. 首页点瀑布流中的一个 进入详细页
  在详细页的
onLoad里向后端发送请求

2. 后端api

一 详细页面的展示 

1. onLoad

// 在首页页面的代码
<navigator url="/pages/newsDetail/newsDetail?newsId={{item.id}}"><image class="img" src="{{item.cover}}" mode="widthFix"></image></navigator>
// 详细页
Pages({
  /**
   * 页面的初始数据
   */
  data: {
    news:{}
  },

  /**
   * 生命周期函数--监听页面加载
   * 
   * 获取页面详细内容
   */
  onLoad: function (options) {
    var newsId = options.newsId
    console.log(newsId)
    wx.request({
    //自己写的url url: api.Newsdetail
+ newsId + /, method: GET, dataType: json, responseType: text, success: (res)=> { if (res.statusCode===200){ this.setData({ news:res.data }) } }, }) }, })

2. 后端API

url(r^newsdetail/(?P<pk>d+)/$, news.NewsViewDetail.as_view()),

 

view.py

class NewsModelViewDetail(serializers.ModelSerializer):
    user = serializers.SerializerMethodField()
    topic = serializers.SerializerMethodField()
  
  # 整合我们要的字段的格式 create_date
= serializers.DateTimeField(format=%Y-%m-%d %H:%M:%S) images = serializers.SerializerMethodField() viewer = serializers.SerializerMethodField() comment = serializers.SerializerMethodField() class Meta: model = models.News exclude = [cover, ] def get_user(self, obj): return model_to_dict(obj.user, fields=[id, nickname, avatar]) def get_topic(self, obj): if not obj.topic: return return model_to_dict(obj.topic, fields=[id, title]) def get_images(self, obj): detail_queryset = models.NewsDetail.objects.filter(news=obj) # return [{‘id‘:item.id,‘path‘:item.cos_path} for item in detail_queryset] # return [item.cos_path for item in detail_queryset] return [model_to_dict(item, fields=[id, cos_path]) for item in detail_queryset] def get_viewer(self, obj): ‘‘‘‘要统计浏览人的总个数 你可以自己一个一个加到数据库,也可以像下面没有注释的方法‘‘‘ # 根据动态的对象 obj(news) # viewer_query = models.ViewerRecord.objects.filter(news=obj).order_by("-id")[0:10] # return [model_to_dict(item.user, fields=[‘nickname‘, ‘avatar‘]) for item in viewer_query] queryset = models.ViewerRecord.objects.filter(news=obj) viewer_list = queryset.order_by(-id)[0:10] context = { count: queryset.count(), result: [model_to_dict(item.user, fields=[nickname, avatar]) for item in viewer_list] } return context def get_comment(self, obj): ‘‘‘ 获取评论的第一条评论,在获取每个评论的第一条的二级评论【也就是展示一条第一级评论在展示一条对一级评论的评论】 :param obj: :return: ‘‘‘ # 1.首先获取所有的一级评论 下面可以用model_to_dict 也可以直接取 value first_queryset = models.CommentRecord.objects.filter(news=obj, depth=1).order_by(-id).values( id, content, depth, user__nickname, user__avatar, create_date ) # 2. 获取二级评论的所有评论 ‘‘‘ second_queryset = models.CommentRecord.objects.filter(news=obj, depth=2).order_by(‘-id‘).values( ‘id‘, ‘content‘, ‘user__nickname‘, ‘user__avatar‘, ‘create_date‘ ) # 2. 获取一级评论下的 二级评论 # first_id_list = [item[‘id‘] for item in first_queryset] # second_queryset = models.CommentRecord.objects.filter(news=obj, depth=2, reply_id__in=first_id_list).order_by(‘-id‘).values(‘id‘,‘content‘,‘user__nickname‘,‘user__avatar‘,‘create_date‘) ‘‘‘ # 2. 获取一级评论下的 二级评论(每个二级评论只取最新的一条) # 获取一级评论的 id first_id_list = [item[id] for item in first_queryset] from django.db.models import Max # 到 values处 就是先取出一级评论下的所有二级评论,在取一个最大的 就是分组取最大 result = models.CommentRecord.objects.filter(news=obj, depth=2, reply_id__in=first_id_list).values( reply_id).annotate(max_id=Max(id)) second_id_list = [item[max_id] for item in result] # 获取二级评论 second_queryset = models.CommentRecord.objects.filter(id__in=second_id_list).values( id, content, depth, user__nickname, user__avatar, create_date, reply_id, reply__user__nickname ) ‘‘‘这个时候我们把第一级评论和第二级评论合并 请看脚本 处理评论结构化 1. 字典的有序 2. 看下面代码 ‘‘‘ import collections first_dict = collections.OrderedDict() first_dict = {} for item in first_queryset: item[create_date] = item[create_date].strftime(%Y-%m-%d %H:%M:%S) first_dict[item[id]] = item for node in second_queryset: node[create_date] = node[create_date].strftime(%Y-%m-%d %H:%M:%S) first_dict[node[reply_id]][child] = [node, ] return first_dict.values() # ① RetrieveAPIView 会自动查出数据库的内容 然后在走我们自定义的序列化 class NewsViewDetail(RetrieveAPIView): queryset = models.News.objects serializer_class = NewsModelViewDetail

 

然后拿到数据之后我们在前端页面展示就可以啦  这里我不在赘述,后面还会有

 

二 评论

上面是每一条一级评论展示一条二级评论 但是我们要看到很多的评论的话 我们就写一个下面的代码

#                                传过去一级评论的id           一级评论的索引 目的是要替换索引位置的值
<text class="click_more" bindtap="click_more_content" data-root="{{item.id}}" data-parent_id={{parent_id}}>点击查看更多</text>

 

# 获取二级评论的所有值
url(r‘^comment/$‘, comment.CommentView.as_view()),
######################################################################
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import ListAPIView
from rest_framework import serializers
from django.forms import model_to_dict
from app01 import models


‘‘‘
# 最开始用的这种方式 但是出来的字段和最开始不一样,所以用下面的方式
class CommenModelSerializert(serializers.ModelSerializer):
create_date = serializers.DateTimeField(‘%Y-%m-%d‘)
user = serializers.SerializerMethodField()
reply_user = serializers.SerializerMethodField()

class Meta:
model = models.CommentRecord
fields = ‘__all__‘

def get_user(self, obj):
return model_to_dict(obj.user, fields=[‘id‘, ‘nickname‘, ‘avatar‘])

def get_reply_user(self, obj):
return model_to_dict(obj.reply.user, fields=[‘id‘, ‘nickname‘])

‘‘‘
class CommenModelSerializert(serializers.ModelSerializer):
create_date = serializers.DateTimeField(‘%Y-%m-%d‘)
user__nickname = serializers.CharField(source=‘user.nickname‘)
user__avatar = serializers.CharField(source=‘user.avatar‘)
reply_id = serializers.CharField(source=‘reply.id‘)
reply__user__nickname = serializers.CharField(source=‘reply.user.nickname‘)

class Meta:
model = models.CommentRecord
# fields = ‘__all__‘
exclude = [‘news‘, ‘user‘, ‘reply‘, ‘root‘]

# 第一步 先看这
class CommentView(APIView):
def get(self, request, *args, **kwargs):
root_id = request.query_params.get(‘root_id‘)
comment_query = models.CommentRecord.objects.filter(root_id=root_id).order_by(‘id‘)

ser = CommenModelSerializert(instance=comment_query, many=True)

return Response(ser.data)
 

 

  /**
   * 点击获取更多二级评论
   */
  click_more_content:function(res){
    var root_id = res.currentTarget.dataset.root;
    var parent_id = res.currentTarget.dataset.parent_id;

    wx.request({
      url: api.CommentAPI,
      data: {
      root_id:root_id
      },
      method: GET,
      dataType: json,
      responseType: text,
      success: (res) => {
        this.setData({
      // 找到所在的位置,然后替换 [
‘news.comment[‘+ parent_id +‘].child‘]:res.data }) }, }) },

三 回复

 前端

技术图片
 <view class="comment">
    <view>全部评论 - {{news.comment.length}} </view>
    <view class="tree">
      <view class="item" wx:for="{{news.comment}}" wx:key="id" wx:for-index="parent_id">
        <image class="big-avatar" src="{{item.user__avatar}}"></image>
        <view class="body">
          <view class="user">

            <view class="name">
              <text>{{item.user__nickname}}</text>
              <text>{{item.create_date}}</text>
            </view>

            <view class="func">
              <text 
              data-news="{{news.id}}" 
              data-reply="{{item.id}}" 
              data-depth="{{item.depth + 1}}" 
              data-nickname="{{item.user__nickname}}"
              data-root="{{item.id}}" 
              bindtap="onClickShowCommentModal">回复</text>

              <text wx:if="{{item.favor}}" class="red">赞</text>

              <text wx:else>赞</text>
            </view>
          </view>
          <!-- 一级评论内容 -->
          <view class="content">
            ## {{item.content}}
          </view>
          <!-- 二级评论内容 -->
          <view class="reply" wx:if="{{item.child}}">
            <view class="row" wx:for="{{item.child}}" wx:key="id" wx:for-item="row">
              <view class="reply-menu">
                <view class="reply-user">
                  <image class="small-avatar" src="{{row.user__avatar}}"></image>
                  <view class="reply-name">
                    <text>#{{row.user__nickname}}</text>
                    <text>{{row.create_date}}</text>
                  </view>
                </view>
                <view class="reply-func">
                // 文章的id 回复的id 深度 +1 头像 根id
                  <text 
                  data-news="{{news.id}}" 
                  data-reply="{{row.id}}" 
                  data-depth="{{row.depth + 1}}" 
                  data-nickname="{{row.nickname}}" 
                  data-root="{{item.id}}"
                  bindtap="onClickShowCommentModal">回复</text>

                  <text wx:if="{{row.favor}}" class="red">赞</text>
                  <text wx:else>赞</text>
                </view>
              </view>
              <view class="reply-content">{{row.content}}</view>

              <text class="click_more" 
              bindtap="click_more_content" 
              data-root="{{item.id}}" 
              data-parent_id={{parent_id}}>点击查看更多</text>
            </view>
          </view>
        </view>
      </view>
    </view>
  </view>
</view>

<!-- 回复 -->
<view class="buttom-view">
  <view class="comment-area" wx:if="{{isShowCommentModal}}">
    <view class="top">
      <image class="big-avatar" src="{{news.user.avatar}}"></image>
      <text>评论</text>
      <!-- 回复一级评论显示一级评论的名字 点击回复按钮显示 -->
      <view class="reply" wx:if="{{reply.reply}}">回复 {{reply.nickname}}
        <icon type="clear" size="15" bindtap="onClickClearReply"></icon>
      </view>
    </view>
    <textarea fixed="true" placeholder="评论内容..." bindinput="inputComment"></textarea>
    <view class="btn">
      <view class="publish" bindtap="onClickPostComment">发布</view>
    </view>

     <!-- 关闭说点什么 -->
    <view class="hide">
      <icon type="cancel" size="30" bindtap="onClickCancelCommentModal"></icon>
    </view>
  </view>
  <!-- 说点什么 -->
  <view class="text-input" wx:else>
    <image class="big-avatar" src="/static/girl.jpg"></image>
    <input placeholder="说点什么..." bindtap="onClickShowCommentModal" data-news="{{news.id}}" data-depth="{{1}}"></input>
  </view>
  <!-- 最开头的view -->
</view>

                    
前端页面

 

技术图片
// pages/newsDetail/newsDetail.js
var api = require(../../config/api.js)
Page({

  /**
   * 页面的初始数据
   */
  data: {
    news:{},
    isShowCommentModal:false,
    reply:{}
  },

  /**
   * 生命周期函数--监听页面加载
   * 
   * 获取页面详细内容
   */
  getNewsDetail(newsid){
    wx.request({
      url: api.Newsdetail + newsid + /,
      method: GET,
      dataType: json,
      responseType: text,
      success: (res) => {
        console.log(第28行, res.data)
        if (res.statusCode === 200) {
          this.setData({
            news: res.data
          })
        }
      },
    })
  },
  onLoad: function (options) {
    var newsid = options.newsId;
    this.getNewsDetail(newsid);
  },
  /**
   * 点击获取更多二级评论
   */
  click_more_content:function(res){
    var root_id = res.currentTarget.dataset.root;
    var parent_id = res.currentTarget.dataset.parent_id;
    wx.request({
      url: api.CommentAPI,
      data: {
      root_id:root_id
      },
      method: GET,
      dataType: json,
      responseType: text,
      success: (res) => {
        console.log(52,res.data)
        this.setData({
          [news.comment[+ parent_id +].child]:res.data
        })
      },
    })
  },
  /**
   * 点击获取输入框 
   */
  onClickShowCommentModal:function(e){
    // {depth: 1, news: 40}
    // {depth: 2, news: 40, nickname: "晓强2", reply: 21, root: 21}
    console.log(e)
    console.log(65,e.currentTarget.dataset)
    this.setData({
      isShowCommentModal:true,
      // 回复一级评论显示一级评论的名字
      reply: e.currentTarget.dataset
    })
    // 自己写的时候有bug 重新获取一下
    var news_id = e.currentTarget.dataset.news
    this.getNewsDetail(news_id)
  },
  /**
  * 点击关闭输入框 
  */
  onClickCancelCommentModal: function () {
    this.setData({
      isShowCommentModal: false
    })
  },
  /**
   * 填写评论内容
   */
  inputComment:function(e){
    // console.log(e.detail.value)
    this.setData({
      ["reply.content"]:e.detail.value
    })
  },
  /**
   * 发布
   */
  onClickPostComment:function(){
    if (!this.data.reply.content){
      wx.showToast({
        title: 请填写评论,
        icon: none,
      })
      return
    }
    wx.request({
      url: api.CommentAPI,
      data: {
        depth:this.data.reply.depth,
        news: this.data.reply.news,       // 回复动态的id
        // nenicknamews: this.data.reply.nickname,
        content: this.data.reply.content,
        reply: this.data.reply.reply,
        root: this.data.reply.root,
      },
      method: POST,
      dataType: json,
      responseType: text,
      success: (res)=> {
        console.log(113,res.data)
        if(res.statusCode==201){
          if (this.data.reply.parent_id == undefined){
            // 如果是根评论
            var dataList = this.data.news.comment
            dataList.unshift(res.data)
            // this.data.news.comment.push()       push     加到最下面
            // this.data.news.comment.unshift()    unshift  加到最上面
            this.setData({
              [news.comment]: dataList,
              [news.comment_count]: this.data.news.comment_count + 1
            })
            this.onClickCancelCommentModal()
          }else{
            // 如果是子评论
            // 1. 根据索引获取二级评论        注意 后台数据要有一级评论要有child字段
            var childcomment = this.data.news.comment[this.data.reply.parent_id].child;
            console.log(123)
            console.log(childcomment)
            console.log(res.data)
            childcomment.unshift(res.data)
            console.log(ssssss,this.data.news)
            this.setData({
              [news.comment[ + this.data.reply.parent_id + ].child]: childcomment,
              [news.comment_count]: this.data.news.comment_count + 1
            })
            this.onClickCancelCommentModal()
          }
        }
      },
    })
  },

  /**
   * 生命周期函数--监听页面初次渲染完成
   */
  onReady: function () {

  },

  /**
   * 生命周期函数--监听页面显示
   */
  onShow: function () {

  },

  /**
   * 生命周期函数--监听页面隐藏
   */
  onHide: function () {

  },

  /**
   * 生命周期函数--监听页面卸载
   */
  onUnload: function () {

  },

  /**
   * 页面相关事件处理函数--监听用户下拉动作
   */
  onPullDownRefresh: function () {

  },

  /**
   * 页面上拉触底事件的处理函数
   */
  onReachBottom: function () {

  },

  /**
   * 用户点击右上角分享
   */
  onShareAppMessage: function () {

  }
})
前端js

 

技术图片
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.generics import ListAPIView
from rest_framework import serializers
from django.forms import model_to_dict
from app01 import models
from rest_framework import status
from django.db.models import F


‘‘‘
class CommenModelSerializert(serializers.ModelSerializer):
    create_date = serializers.DateTimeField(‘%Y-%m-%d‘)
    user = serializers.SerializerMethodField()
    reply_user = serializers.SerializerMethodField()

    class Meta:
        model = models.CommentRecord
        fields = ‘__all__‘

    def get_user(self, obj):
        return model_to_dict(obj.user, fields=[‘id‘, ‘nickname‘, ‘avatar‘])

    def get_reply_user(self, obj):
        return model_to_dict(obj.reply.user, fields=[‘id‘, ‘nickname‘])

‘‘‘
class CommenModelSerializert(serializers.ModelSerializer):
    create_date = serializers.DateTimeField(%Y-%m-%d)
    user__nickname = serializers.CharField(source=user.nickname)
    user__avatar = serializers.CharField(source=user.avatar)
    reply_id = serializers.CharField(source=reply.id)
    reply__user__nickname = serializers.CharField(source=reply.user.nickname)

    class Meta:
        model = models.CommentRecord
        # fields = ‘__all__‘
        exclude = [news, user, reply, root]



class CreateCommenModelSerializert(serializers.ModelSerializer):
    create_date = serializers.DateTimeField(%Y-%m-%d, read_only=True)
    user__nickname = serializers.CharField(source=user.nickname, read_only=True)
    user__avatar = serializers.CharField(source=user.avatar, read_only=True)
    reply_id = serializers.CharField(source=reply.id, read_only=True)
    reply__user__nickname = serializers.CharField(source=reply.user.nickname, read_only=True)

    class Meta:
        model = models.CommentRecord
        # fields = ‘__all__‘
        exclude = [user, favor_count]



class CommentView(APIView):
    def get(self, request, *args, **kwargs):
        root_id = request.query_params.get(root_id)

        comment_query = models.CommentRecord.objects.filter(root_id=root_id).order_by(id)

        ser = CommenModelSerializert(instance=comment_query, many=True)

        return Response(ser.data)

    def post(self, request, *args, **kwargs):

        # 1.进行数据校验    序列化 news/ depth/reply/content/root
        ser = CreateCommenModelSerializert(data=request.data)
        # 2.校验通过 保存数据库
        if ser.is_valid():
            # 保存到数据库
            ser.save(user_id=1)
            # 对新增的数据值进行序列化【数据格式要调整 参考上面的read_only创建的时候校验,传过去不校验】
            print(ser.data)
            new_id= ser.data.get(news)
            models.News.objects.filter(id=new_id).update(comment_count=F(comment_count)+1)
            return Response(ser.data,status=status.HTTP_201_CREATED)
        return Response(ser.errors)
        # 3.将保存到数据库的数据再返回小程序页面(小程序页面要展示)
后端逻辑

 

后续会添加  点赞文章 点赞评论 关注等

 

以上是关于(二十)首页内容详细详细页+ 评论 + 回复的主要内容,如果未能解决你的问题,请参考以下文章

dedecms的首页内容页列表页中 动态JS调用评论数

dedecms的首页内容页列表页中 动态JS调用评论数

手撕Resnet卷积神经网络-pytorch-详细注释版(可以直接替换自己数据集)-直接放置自己的数据集就能直接跑。跑的代码有问题的可以在评论区指出,看到了会回复。训练代码和预测代码均有。

php评论回复功能

详细页面接口制作展示

python 3+djanjo 2.0.7简单学习(三)--Django视图