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项目(二) 可以在本地写 ...
随机推荐
- 03-Python基础2
本节内容 1. 函数基本语法及特性 2. 参数与局部变量 3. 返回值 嵌套函数 4.递归 5.匿名函数 6.函数式编程介绍 7.高阶函数 8.内置函数 温故知新 1. 集合 主要作用: 去重 关系测 ...
- Spring Cloud 系列之 Alibaba Nacos 注册中心(二)
本篇文章为系列文章,未读第一集的同学请猛戳这里:Spring Cloud 系列之 Alibaba Nacos 注册中心(一) 本篇文章讲解 Nacos 注册中心集群环境搭建. Nacos 集群环境搭建 ...
- pip应用实例
homepage 目录 1. 安装 1.1. 指定版本 1.2. 用户权限 1.3. 读取requirments.txt 1.4. 不使用缓存文件 1.5. 指定extras_require 2. 镜 ...
- Win10下Tensorflow的安装
Win10下Tensorflow的安装 1. Tensorflow简介 TensorFlow是谷歌基于DistBelief进行研发的第二代人工智能学习系统,其命名来源于本身的运行原理.Tensor(张 ...
- Flask URL构建
Flask URL构建 url_for()函数对于动态构建特定函数的URL非常有用.该函数接受函数的名称作为第一个参数,以及一个或多个关键字参数,每个参数对应于URL的变量部分. 以下脚本演示了如何使 ...
- 使用本地shadow socks代理
1,第一种方式 import urllib2 import socks from sockshandler import SocksiPyHandler opener = urllib2.build_ ...
- 用VC++6.0,双击主对话框中的按钮时,不能跳转到代码处
1. 首先在项目中--[生成]build--[清除解决方案]clean 2. 关闭项目 3. 删除项目中的[Debug]下所有文件 4. 把*.aps,*.clw,*.ncb,*.opt删掉----- ...
- 使用SpringCloud Stream结合rabbitMQ实现消息消费失败重发机制
前言:实际项目中经常遇到消息消费失败了,要进行消息的重发.比如支付消息消费失败后,要分不同时间段进行N次的消息重发提醒. 本文模拟场景 当金额少于100时,消息消费成功 当金额大于100,小于200时 ...
- PHPWord中文乱码、单元格合并、动态表格模板解决方案合集
摘要: 最近一个项目开发要用到PHP技术导出Word文档,采用PHPWord插件,版本为0.6.2 beta,CodePlex已停止维护.网上还有另外一个版本的PhpWord,项目类名大小写上略有不 ...
- JavaWeb网上图书商城完整项目--day02-20.修改密码各层实现
1.我们来看看后台操作的业务流程 每一层都按照上面的步骤来进行实现: 这里我们要使用commUtils.toBean把表单提交的参数封装成User对象,必须保证User对象中的字段和表单提交的字段的名 ...