day74 bbs项目☞点赞与评论
整体总结:
- 在出现bug的时候,先判断是前端bug还是后端bug,再判断bug错误类型,以及报错信息
- 如果出现bug但是没报错,可以通过后端用print分段代码,前端用consloe方式分段
- 大部分功能逻辑其实都是类似,比如点赞和评论,views都写到了判断是否登录,判断是否是ajax请求等等,真正展示功能特性的代码其实就两三行,所以要分清主次
- 前端注意的就是标签的查找,绑定事件的使用,标签属性的修改,标签内容的修改,ajax请求,部分DOM操作,以上必须数量掌握
- 后端最容易出错的应该是连表和跨表查询的写法
一、文章详情展示
总结注意点:
- url顶替问题,注意url顺序和正则的优先级
- 多次用到同一块页面可以制作成inclusion_tag
- 模版的继承基本语法要熟练掌握
1 将侧边栏做成inclusion_tag
left_menu.html
<div class="panel panel-default">
  <div class="panel-heading">文章标签</div>
  <div class="panel-body">
    {% for tag in tag_list %}
        <p><a href="/{{ username }}/tag/{{ tag.2 }}">{{ tag.0 }} ({{ tag.1 }})</a></p>
    {% endfor %}
  </div>
</div>
<div class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title " >文章分类</h3>
  </div>
  <div class="panel-body">
    {% for category in category_list %}
        <p><a href="/{{ username }}/category/{{ category.2 }}">{{ category.0 }} ({{ category.1 }})</a></p>
    {% endfor %}
  </div>
</div>
<div class="panel panel-default">
  <div class="panel-heading">
    <h3 class="panel-title " >日期</h3>
  </div>
  <div class="panel-body">
    {% for date in date_list %}
        <p><a href="/{{ username }}/archive/{{ date.0|date:'Y-m' }}">{{ date.0 }} ({{ date.1 }})</a></p>
    {% endfor %}
  </div>
</div>
在项目中创建一个templatetags文件夹(固定名称)然后在该文件夹内创建一个任意名称的py文件
mytag.py
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
    category_list = models.Category.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values_list(
        'name', 'count_num', 'pk')
    # 2 查询当前用户下所有的标签下的文章数
    tag_list = models.Tag.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values_list('name',
                                                                                                         'count_num',
                                                                                                         'pk')
    # 3 以创建日期为分类
    date_list = models.Article.objects.filter(blog=blog).annotate(mouth=TruncMonth('create_time')).values(
        'mouth').annotate(count_num=Count('pk')).values_list('mouth', 'count_num')
    return locals()
展示文章详情的视图函数
views.py
通过前端点击返回给后端需要的数据,然后筛选得到具体的文章对象
def article_detail(request, username, article_id):
    article_obj = models.Article.objects.filter(pk=article_id, blog__userinfo__username=username).first()
    if not article_obj:
        return render(request, 'errors.html')
    comment_list = models.Comment.objects.filter(article=article_obj)
    return render(request, 'article_detail.html', locals())
二、点赞点踩功能
总结注意点:
- if嵌套的时候尽量先把正确的逻辑写好再写错误的逻辑
- F查询对字段的修改
- 传给前端的数据如果是一段html代码,可以通过.html('')的方法去渲染
- 绑定点击事件的时候尽量绑定大一点的div,不然绑定太小了怎么错的都不知道
- 重点区分jquery的一些常用方法,记住使用规律
views.py
import json
from django.db.models import F
def up_or_down(request):
    if request.is_ajax():
        back_dic = {'code': 2000}
        # 判断用户是否登录
        if request.user.is_authenticated():
            article_id = request.POST.get('article_id')
            article_obj = models.Article.objects.filter(pk=article_id).first()
            # 判断操作的是否是自己的文章
            if article_obj.blog.userinfo.username != request.user:
                # 判断用户是否给这个文章点赞过
                is_used = models.UpAndDowm.objects.filter(user=request.user, article=article_obj)
                if not is_used:
                    print(666)
                    # 在两张表内存储点赞点踩
                    is_up = request.POST.get('is_up')
                    is_up = json.loads(is_up)
                    back_dic['code'] = 1000
                    print(is_up)
                    # 点赞
                    if is_up:
                        back_dic['msg'] = '点赞成功!'
                        models.Article.objects.filter(pk=article_id).update(up_num=F('up_num') + 1)
                    else:
                        back_dic['msg'] = '点踩成功!'
                        print(back_dic)
                        models.Article.objects.filter(pk=article_id).update(dowm_num=F('dowm_num') + 1)
                    models.UpAndDowm.objects.create(user=request.user, article=article_obj, is_up=is_up)
                else:
                    back_dic['msg'] = '不能给已操作过的文章点赞点踩!'
            else:
                back_dic['msg'] = '不能给自己的文章点赞点踩!'
        else:
            back_dic['msg'] = '请先<a href="/login/">登录</a>'
        return JsonResponse(back_dic)
article_detail.html
{% block css %}
// 样式都是copy别人写好的,有能cv的就别自己写
    <style>
        #div_digg {
            float: right;
            margin-bottom: 10px;
            margin-right: 30px;
            font-size: 12px;
            width: 128px;
            text-align: center;
            margin-top: 10px;
        }
        .diggit {
            float: left;
            width: 46px;
            height: 52px;
            background: url('/static/img/upup.gif') no-repeat;
            text-align: center;
            cursor: pointer;
            margin-top: 2px;
            padding-top: 5px;
        }
        .buryit {
            float: right;
            margin-left: 20px;
            width: 46px;
            height: 52px;
            background: url('/static/img/downdown.gif') no-repeat;
            text-align: center;
            cursor: pointer;
            margin-top: 2px;
            padding-top: 5px;
        }
        .clear {
            clear: both;
        }
    </style>
{% endblock %}
{% block content %}
<h2>{{ article_obj.title }}</h2>
    <div class="article-content">
        {{ article_obj.content|safe }}
    </div>
<div class="clearfix">
    <div id="div_digg">
    <div class="diggit action">
        <span class="diggnum" id="digg_count" up_or_down = 'true'>{{ article_obj.up_num }}</span>
    </div>
    <div class="buryit action">
        <span class="burynum" id="bury_count" up_or_down = 'false'>{{ article_obj.dowm_num }}</span>
    </div>
    <div class="clear"></div>
    <div class="diggword" id="digg_tips" style="color: red;"></div>
</div>
</div>
 //   给所有的action类绑定事件
    $('.action').click(function () {
        {#alert($(this).hasClass('diggit'))#}
        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 == 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)
                    }
            }
        })
    })
三、评论功能
总结注意点:
- 在一张表中有一个字段和表本身关联的时候,需要注意必须可以为空
- 有一些同时删除同时跟新的操作在没有外键关联的情况下可以使用事务
- 当我们在前端做一些对值的判断操作时,必须注意这个值是否需要清空
views.py
def comment(request):
    if request.is_ajax():
        back_dic = {'code': 2000}
        if request.method == 'POST':
            if request.user.is_authenticated():
                article_id = request.POST.get('article_id')
                content = request.POST.get('content')
                parent_id = request.POST.get('parent_id')
                with transaction.atomic():
                    models.Article.objects.filter(pk=article_id).update(comment_num=F('comment_num') + 1)
                    models.Comment.objects.create(user=request.user, article_id=article_id, content=content,
                                                  parent_id=parent_id)
                back_dic['code'] = 1000
                back_dic['msg'] = '评论成功'
                print(back_dic)
        return JsonResponse(back_dic)
article_detail.html
<div>
    <ul class="list-group">
        {% for comment in comment_list %}
            <li class="list-group-item">
                <span>#{{ forloop.counter }}楼</span>
                <span>{{ comment.comment_time|date:'Y-m-d' }}</span>
                <span>{{ comment.user.username }}</span>
                <span><a class="pull-right reply" username="{{ comment.user.username }}" comment_id="{{ comment.pk }}">回复</a></span>
                <div>
                    {% if comment.parent_id %}
                        <p>@{{ comment.parent.user.username }}</p>
                    {% endif %}
                    {{ comment.content }}
                </div>
            </li>
        {% endfor %}
    </ul>
</div>
{#    渲染评论楼#}
{% if request.user.is_authenticated %}
     <div>
        <p><span class="glyphicon glyphicon-comment"></span>发表评论</p>
        <div>
            <textarea name="comment" id="id_comment" cols="60" rows="10" ></textarea>
        </div>
        <button class="btn btn-primary" id="id_submit">提交评论</button>
        <span style="color: red" id="errors"></span>
    </div>
        {% else %}
                <li><a href="{% url 'reg' %}">注册</a></li>
                <li><a href="{% url 'login' %}">登陆</a></li>
{% endif %}
      $.ajax({
            url:'/comment/',
            type:'post',
            data:{
                'article_id':'{{ article_id }}',
                'content':content,
                'parent_id':parent_id,
                'csrfmiddlewaretoken': '{{ csrf_token }}',
            },
            success:function (args) {
                if(args.code==1000){
                    $('#errors').text('{{ args.msg }}');
                    $('#id_comment').val('');
                    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>`
                    $('.list-group').append(temp);
                    parent_id = null;
                }
            }
        })
    })
    $('.reply').click(function () {
        let commentUserName = $(this).attr('username');
        parent_id = $(this).attr('comment_id');
        $('#id_comment').val('@'+commentUserName+'\n').focus()
    })
day74 bbs项目☞点赞与评论的更多相关文章
- BBS项目分布搭建四(点赞点踩及评论功能准备)
		BBS项目分布搭建四(点赞点踩及评论功能) 1. 点赞点踩样式准备 # 在base.html文件中 head标签内 添加css模块: {% block css %} {% endblock %} # ... 
- tornado web高级开发项目之抽屉官网的页面登陆验证、form验证、点赞、评论、文章分页处理、发送邮箱验证码、登陆验证码、注册、发布文章、上传图片
		本博文将一步步带领你实现抽屉官网的各种功能:包括登陆.注册.发送邮箱验证码.登陆验证码.页面登陆验证.发布文章.上传图片.form验证.点赞.评论.文章分页处理以及基于tornado的后端和ajax的 ... 
- BBS项目分布搭建五(评论相关功能实现)
		BBS项目分布搭建五(评论相关) 1. 根评论逻辑实现 # 在models.py文件中 修改: # 7. 评论表 parent = models.ForeignKey(to='self', null= ... 
- BBS论坛  文章详情、点赞、评论
		六.文章详情.点赞.评论 文章详情页面: def article_detail(request, username, article_id): # user_obj = models.UserInfo ... 
- auth复习和BBS项目的登录(1)
		auth复习 auth组件 验证:authenticate(request,username='andy',password='123) 登录:login(request,user) 注销:login ... 
- python 自动化之路 day 20 Django进阶/BBS项目【一】
		一.django进阶 1.django orm 增删改查 1.1.创建表: 1 2 3 >>> from blog.models import Blog >>> b ... 
- day75 bbs项目☞后台管理+修改头像
		目录 一.后台管理之添加文章 二.修改用户头像 bbs项目总结 一.后台管理之添加文章 添加文章有两个需要注意的问题: 文章的简介切取,应该想办法获取到当前文章的文本内容后再截取字符 XSS攻击,由于 ... 
- BBS项目(一)
		目录 BBS项目(一) 项目开发流程 BBS项目 BBS表分析 自关联 表关系图示 BBS项目(一) 项目开发流程 项目分类 针对互联网用户:抖音,淘宝····· 针对公司内部:后台管理系统··· 针 ... 
- BBS项目(二)
		目录 BBS项目(二) ORM 创建相关表 表模型 修改admin样式 Simple-UI 注册表添加数据 注册forms类编写 注册功能前端搭建 头像实时显示功能实现 BBS项目(二) 可以在本地写 ... 
随机推荐
- 制作seata docker镜像
			seata是阿里巴巴的一款开源的分布式事务框架,官方已经支持docker了,但是因为业务的需要,需要自己定制. 制作docker镜像 官方的Dockerfile.下载seata-server-1.1. ... 
- MYSQL 实现ROWNO功能
			select tt.rowno from( select (@rownum:=@rownum+1) as rowno, t.id from news t ,(select (@rownum : ... 
- 【优雅写代码系统】springboot+mybatis+pagehelper+mybatisplus+druid教你如何优雅写代码
			目录 spring基本搭建 整合mybatis pom配置 mybatis配置 设置数据源 设置sqlsessionfactory 设置扫描 设置开启事务 资源放行 测试 结果 思考&& ... 
- 数据源管理 | Kafka集群环境搭建,消息存储机制详解
			本文源码:GitHub·点这里 || GitEE·点这里 一.Kafka集群环境 1.环境版本 版本:kafka2.11,zookeeper3.4 注意:这里zookeeper3.4也是基于集群模式部 ... 
- SpringBoot爬坑系列
			1.日志篇 现象 由于日志配置采用原来SpringMVC项目中的log4j.properties 文件,日志采用springboot自带的jar包会出现打印不出日志的情况. 解决 引入原日志包 < ... 
- RabbitMQ是什么
			1.引入MQ 1.1什么是MQ  MQ(Message Quene):翻译为 消息队列,通过典型的 生产者 和 消费者 模型,生产者不断向消息队列中生产消息,消费者不断的从队列中获取消息.因为消息的 ... 
- Python惯用法
			目录 1. 不要使用可变类型作为参数的默认值 1. 不要使用可变类型作为参数的默认值 摘自<流畅的Python>8.4.1 class HauntedBus: ""&q ... 
- git clone 时注意点
			环境: 在公司访问外网需要设置代理,另外,在公司局域网内架设了一台 GIT 服务器. 在使用 git clone 时,不能设置成 git 使用代理: git config --global http. ... 
- 调用webservice接口,报错:(十六进制值0x01)是无效的字符
			#事故现场 调用webservice接口,报错:(十六进制值0x01)是无效的字符. 如图: 意思是webservice返回的信息中包含无效的字符,无法解析成xml: #分析 使用postman向we ... 
- Divisors (求解组合数因子个数)【唯一分解定理】
			Divisors 题目链接(点击) Your task in this problem is to determine the number of divisors of Cnk. Just for ... 
