• BBS项目之点赞点踩功能


    BBS项目之点赞点踩功能

    需求分析

    # 需求1
    已经支持过的用户(点赞,点擦)不能再点
    # 需求2
    未经过认证的用户(匿名用户)不能点赞点踩,需要让其(登录或注册账号)
    # 需求3
    该文章的作者不能给自己的文章点赞
    

    这里需要注意的是:点赞数点踩数是出现较为频繁的数据字段,但凡文章出现的地方,其也随之出现,为了避免频繁的跨表查询,对数据库查询进行优化,在Article 表中引入up_num,down_num。由此,引入了需求4。

    # 需求4
    文章表和点赞点踩表,需要同时进行数据更新,这里利用事务的一致性进行处理
    

    文章表结构

    class Article(models.Model):
        """文章表"""
        title = models.CharField(verbose_name='文章标题', max_length=64)
        desc = models.CharField(verbose_name='文章简介', max_length=255)
        # 文章内容有很多,一般使用TextField
        content = models.TextField(verbose_name='文章内容')
        create_time = models.DateField(auto_now_add=True)
    
        # 数据库字段优化设计(避免频繁的跨表查询操作)
        up_num = models.BigIntegerField(verbose_name='点赞数', default=0)
        down_num = models.BigIntegerField(verbose_name='点踩数', default=0)
        comment_num = models.BigIntegerField(verbose_name='评论数', default=0)
    
        # 外键字段
        # 一个站点有多篇文章(一对多)
        blog = models.ForeignKey(to='Blog', null=True)
        # 一个分类有多篇文章(一对多)
        category = models.ForeignKey(to='Category', null=True)
        # 一个标签下游多篇文章,一篇文章可以有多个标签(多对多)
        tags = models.ManyToManyField(to='Tag',
                                      through='Article2Tag',
                                      through_fields=('article', 'tag'),
                                      )
    

    点赞点踩表结构

    class UpAndDown(models.Model):
        """点赞点踩表"""
        user = models.ForeignKey(to='UserInfo')
        article = models.ForeignKey(to='Article')
        is_up = models.BooleanField()  # 传布尔值,数据库中存0/1
    

    业务逻辑

    前端:

    # 点赞和点踩触发的是同一事件,通过ajax请求向后端提交数据;
    # 点赞和点踩的不同之处在于,他们的布尔值不同,在数据库中存储为is_up(0/1);
    # 当用户点完赞/踩后,前端页面是即时更新的,可以通过DOM操作,而不是render渲染。
    

    后端:

    # 匿名用户不支持点赞/点踩
    # 文章作者不支持点赞/点踩
    # 评论过的用户不支持点赞/点踩
    

    基于以上的逻辑,进行如下的设计。

    代码

    前端

    {# 点赞点踩开始 #}
            <div class="clearfix">
                <div id="div_digg">
                    <div class="diggit action">
                        <span class="diggnum" id="digg_count">{{ article_obj.up_num }}</span>
                    </div>
                    <div class="buryit action">
                        <span class="burynum" id="bury_count">{{ article_obj.down_num }}</span>
                    </div>
                    <div class="clear"></div>
                    <div class="diggword" id="digg_tips" style="color: red;"></div>
                </div>
            </div>
            {# 点赞点踩结束 #}
    
    //给所有的action绑定事件
            $('.action').click(function () {
                let isUp = $(this).hasClass('diggit'); //判断是不是赞图片被点击了,它返回的是一个布尔值
                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 === 1500) {
                            //将前端的数字加1
                            let old_num = $div.children().text();
                            $div.children().text(Number(old_num) + 1);
                            $('.diggword').html(args.msg)
                        } else (
                            $('.diggword').html(args.msg)
                        )
                    }
                })
            });
    
    

    后端

    def up_or_down(request):
        if request.is_ajax():
            back_dict = {'code': 1500, 'msg': ''}
            # 判断当前用户是否登录
            if request.user.is_authenticated():
                article_id = request.POST.get('article_id')
                is_up = json.loads(request.POST.get('is_up'))
                article_obj = models.Article.objects.filter(pk=article_id).first()
                # 判断当前的文章是否是当前用户写的
                if not article_obj.blog.userinfo == request.user:
                    # 校验当前用户是否已经点过了(哪个地方记录了用户到底点了还是没有点)
                    is_click = models.UpAndDown.objects.filter(user=request.user, article=article_obj)
                    if not is_click:
                        # 操作数据库来记录数据库   要同步article表中的普通字段
                        if is_up:
                            # 给点赞数加1
                            
                            
            # 利用F查询来获取表字段加1
            models.Article.objects.filter(pk=article_id).update(up_num=F('up_num') + 1)
                            back_dict['msg'] = '点赞成功'
                        else:
                            # 给点踩数加1
                            models.Article.objects.filter(pk=article_id).update(down_num=F('down_num') + 1)
                            back_dict['msg'] = '点踩成功' 
                        # 操作点赞点踩表
                        models.UpAndDown.objects.create(user=request.user, article=article_obj, is_up=is_up)
                    else:
                        # 查询已经点过的是赞还是踩
                        up_or_down_obj = models.UpAndDown.objects.filter(user=request.user, article=article_obj).first()
                        once_click_up = up_or_down_obj.is_up
                        back_dict['code'] = 1501
                        back_dict['msg'] = '您已经支持过(赞)' if once_click_up else '您已经支持过(踩)'
                else:
                    back_dict['code'] = 1502
                    back_dict['msg'] = '不能给自己的文章投票'
            else:
                back_dict['code'] = 1503
                back_dict['msg'] = '<a href="/login/" style="text-decoration: none;color: red;">请先登录</a>'
    
            return JsonResponse(back_dict)
    
  • 相关阅读:
    导出大智慧L2要密码的公式
    SQL Server 索引结构及其使用
    职业式证券交易全貌向职业交易员进军者鉴[转]
    sqlite多字段拼接方法
    推荐两个UI、PSD文件搜索网站
    利用事件冒泡和阻止事件冒泡的例子
    js通过八个点 拖动改变div大小
    匿名函数运用js脚本一对圆括号
    js对象转换为json格式的jquery辅助类
    简单清晰的缓冲运动框架
  • 原文地址:https://www.cnblogs.com/surpass123/p/13149952.html
Copyright © 2020-2023  润新知