ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

BBS03--文章详情页、点赞点踩、文章评论

2022-07-30 13:34:17  阅读:166  来源: 互联网

标签:点赞点 -- request up 评论 user 文章 article


1 文章详情页

# url设计
  /username/article/1

# 先验证url是否会被其他url顶替

# 文章详情页和个人站点基本一致 所以用模版继承

# 侧边栏的渲染需要传输数据才能渲染 并且该侧边栏在很多页面都需要使用
  1.哪个地方用就拷贝需要的代码(不推荐 有点繁琐)
  2.将侧边栏制作成inclusion_tag	


# 自定义模板步骤:
  1.在应用下创建一个名字必须叫templatetags文件夹
  2.在该文件夹内创建一个任意名称的py文件
  3.在该py文件内先固定写两行代码
    from django import template
    register = template.Library()
    # 自定义过滤器
    # 自定义标签
    # 自定义inclusion_tag


# 自定义inclusion_tag:left_menu
from django import template
from app01 import models
from django.db.models import Count
from django.db.models.functions import TruncMonth

register = template.Library()


@register.inclusion_tag('left_menu.html')
def left_menu(username):
    # 构造侧边栏需要的数据
    user_obj = models.UserInfo.objects.filter(username=username).first()
    blog = user_obj.blog

    # 左侧三个筛选 (侧边栏的筛选其实就是对article_list再进一步筛选)
    # 1.查询个人站点的文章分类及分类下的文章数
    category_list = models.Category.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values(
        'name', 'count_num', 'pk')

    # 2.查询个人站点的文章标签及标签下的文章
    tag_list = models.Tag.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values(
        'name', 'count_num', 'pk')

    # 3.查询个人站点下的文章时间及时间下的文章数
    date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values(
        'month').annotate(count_num=Count('id')).values('month', 'count_num').order_by('month')
    return locals()

2 文章点赞点踩

2.1 逻辑梳理

# 引入:
  1.浏览器上你看到的花里胡哨的页面,内部都是HTML(前端)代码
  2.那现在我们的文章内容应该写什么???	>>> html代码
  3.如何拷贝文章
    博客园文章--copy outerhtml

  4.拷贝点赞点踩
    1.拷贝前端点赞点踩图标 只拷了html
    2.css也要拷贝
        由于有图片防盗链的问题 所以将图片直接下载到本地

# 课下思考:
  前端如何区分用户是点了赞还是点了踩
    1.给标签各自绑定一个事件
      两个标签对应的代码其实基本一样,仅仅是是否点赞点踩这一个参数不一样而已
    2.二合一
      给两个标签绑定一个事件
        
    # 给所有的action类绑定事件
    $('.action').click(function () {
        alert($(this).hasClass('diggit'))
    })

# 由于点赞点踩内部有一定的业务逻辑,所以后端单独开设视图函数处理



# 前端页面
  1.拷贝博客园点赞点踩前端样式
    html代码 + css代码
  2.如何判断用户到底点击了哪个图标
    恰巧页面上只有两个图标,所以给两个图标标签添加一个公共的样式类
    然后给这个样式类绑定点击事件
    再利用this指代的就是当前被操作对象 
    利用hasClass判断是否有某个特定的类属性,
    从而判断出到底是两个图标中的哪一个
  3.书写ajax代码朝后端提交数据
  
  4.后端逻辑书写完毕之后 前端针对点赞点踩动作实现需要动态展示提示信息
      1.前端点赞点踩数字自增1 需要注意数据类型的问题
            Number(old_num) + 1
      2.用户没有登陆 需要展示没有登陆提示 并且登陆可以点击跳转
            html()
            |safe
            mark_safe()
# 后端逻辑
  1.先判断用户是否登陆
    request.user.authenticated()
  2.再判断当前文字是否是当前用户自己写的
    通过文章主键值获取文章对象
    之后利用orm查询获取文章对象对应的用户对象与request.user比对
  3.判断当前用户是否已经给当前文章点了
    利用article_obj文章对象和request.user用户对象去点赞点踩表中筛选数据如果有数据则点过没有则没点
  4.操作数据库	需要注意要同时操作两张表
    # 前端发送过来的是否点赞是一个字符串 需要你自己转成布尔值或者用字符串判断
    is_up = json.loads(is_up)
    F模块

2.2 代码实现

##### views.py 

# 个人建议:
   写代码先把所有正确的逻辑写完 再去考虑错误的逻辑 不要试图两者兼得

import json
from django.db.models import F
def up_or_down(request):
    """
    1.校验用户是否登陆
    2.判断当前文章是否是当前用户自己写的(自己不能点自己的文章)
    3.当前用户是否已经给当前文章点过了
    4.操作数据库
    """
    if request.is_ajax():
        back_dic = {'code':1000,'msg':''}
        # 1 先判断当前用户是否登陆
        if request.user.is_authenticated():
            article_id = request.POST.get('article_id')
            is_up = request.POST.get('is_up')
            is_up = json.loads(is_up)  # 记得类型转换
            # print(is_up, type(is_up))  # True <class 'bool'>
            # 2 判断当前文章是否是当前用户自己写的  根据文章id查询文章对象 根据文章对象查作者 根request.user比对
            article_obj = models.Article.objects.filter(pk=article_id).first()
            if not article_obj.blog.userinfo == request.user:
                # 3 校验当前用户是否已经点了      哪个地方记录了用户到底点没点
                is_click = models.UpAndDown.objects.filter(user=request.user,article=article_obj)
                if not is_click:
                    # 4 操作数据库 记录数据      要同步操作普通字段
                    # 判断当前用户点了赞还是踩 从而决定给哪个字段加一
                    if is_up:
                        # 给点赞数加一
                        models.Article.objects.filter(pk=article_id).update(up_num = F('up_num') + 1)
                        back_dic['msg'] = '点赞成功'
                    else:
                        # 给点踩数加一
                        models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
                        back_dic['msg'] = '点踩成功'
                    # 操作点赞点踩表
                    models.UpAndDown.objects.create(user=request.user,article=article_obj,is_up=is_up)
                else:
                    back_dic['code'] = 1001
                    back_dic['msg'] = '你已经点过了,不能再点了'  
                    # 这里你可以做的更加的详细 提示用户到底点了赞还是点了踩
            else:
                back_dic['code'] = 1002
                back_dic['msg'] = '你个臭不要脸的!'
        else:
            back_dic['code'] = 1003
            back_dic['msg'] = '请先<a href="/login/">登陆</a>'
        return JsonResponse(back_dic)

    
    
#### article_detail.html    
<script>
    //  给所有的action类绑定事件
    $('.action').click(function () {
        let isUp = $(this).hasClass('diggit');    # digg  n.推荐   bury  n.埋葬
        let $div = $(this);
        // 朝后端发送ajax请求
        $.ajax({
            url:'/up_or_down/',
            type:'post',
            data:{
                'article_id':'{{ article_obj.pk }}',
                'is_up':isUp,
                'csrfmiddlewaretoken':'{{ csrf_token }}'
            },
            success:function (args) {
                    if(args.code == 1000){
                        $('#digg_tips').text(args.msg)
                        // 将前端的数字加一
                        // 先获取到之前的数字
                        let oldNum = $div.children().text();  // 文本 是字符类型
                        // 易错点
                        $div.children().text(Number(oldNum) + 1)  // 字符串拼接了 1+1 = 11  11 + 1 = 111
                    }else{
                        $('#digg_tips').html(args.msg)
                    }
            }
        })
    })
</script>

3 文章评论

# 顺序:
  先根评论
  再子评论

# 根评论
    先把整体的评论功能跑通 再去填补
    
  1.书写前端获取用户评论的标签
    可能点赞点踩有浮动带来的影响
    	clearfix
  2.点击评论按钮发送ajax请求
  
  3.后端针对评论单独开设url处理
    后端逻辑其实非常的简单非常的少
    
  4.针对根评论涉及到前端的两种渲染方式
    1.DOM操作临时渲染评论楼
    	需要用到模版字符串
      	// 临时渲染评论楼
        let userName = '{{ request.user.username }}';
        let temp = `
        <li class="list-group-item">
            <span>${userName}</span>
            <span><a href="#" class="pull-right">回复</a></span>
            <div>
                ${conTent}
            </div>
        </li>
        `
        // 将生成好的标签添加到ul标签内
        $('.list-group').append(temp);
        
    2.页面刷新 永久渲染(render)
    	后端直接获取当前文章对应的所有评论 传递给html页面即可
      前端利用for循环参考博客园评论楼样式渲染评论
      
    3.评论框里面的内容需要清空

   
# 子评论
    从回复按钮入手
    
  点击回复按钮发生了哪些事
    1.评论框自动聚焦	.focus()
    2.评论框里面自动添加对应评论的评论人姓名
        @username\n
    3.评论框内部自动换行
     
        
  # 点击回复按钮之后 我们应该获取到根评论对应的用户名和主键值
    针对主键值 多个函数都需要用 所以用全局变量的形式存储
    
  # 针对子评论内容 需要切割出不是用户写的	"@username\n"
    // 获取用户评论的内容
    let conTent = $('#id_comment').val();
    // 判断当前评论是否是子评论 如果是 需要将我们之前手动渲染的@username去除
    if(parentId){
        // 找到\n对应的索引 然后利用切片 但是前片顾头不顾尾 所以索引+1
       let indexNum = conTent.indexOf('\n') + 1;
       conTent = conTent.slice(indexNum)  // 将indexNum之前的所有数据切除 只保留后面的部分
    }
    
   # 后端parent字段本来就可以为空,所以传不传值 都可以直接存储数据
    
   # 前端针对子评论再渲染评论楼的时候 需要额外的判断
      {% if comment.parent_id %}
           <p>@{{ comment.parent.user.username }}</p>
      {% endif %}
           {{ comment.content }}
        
   # 前端parentId字段每次提交之后需要手动清空 



# 思考:
  1.根评论和子评论点的是同一个按钮: parent_id
    
  2.根评论和子评论的区别
    子评论在其实跟评论的ajax代码中 只需要添加一个父评论id即可

标签:点赞点,--,request,up,评论,user,文章,article
来源: https://www.cnblogs.com/Edmondhui/p/16534793.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有