整体总结:

  1. 在出现bug的时候,先判断是前端bug还是后端bug,再判断bug错误类型,以及报错信息
  2. 如果出现bug但是没报错,可以通过后端用print分段代码,前端用consloe方式分段
  3. 大部分功能逻辑其实都是类似,比如点赞和评论,views都写到了判断是否登录,判断是否是ajax请求等等,真正展示功能特性的代码其实就两三行,所以要分清主次
  4. 前端注意的就是标签的查找,绑定事件的使用,标签属性的修改,标签内容的修改,ajax请求,部分DOM操作,以上必须数量掌握
  5. 后端最容易出错的应该是连表和跨表查询的写法

一、文章详情展示

总结注意点:

  1. url顶替问题,注意url顺序和正则的优先级
  2. 多次用到同一块页面可以制作成inclusion_tag
  3. 模版的继承基本语法要熟练掌握

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())

二、点赞点踩功能

总结注意点:

  1. if嵌套的时候尽量先把正确的逻辑写好再写错误的逻辑
  2. F查询对字段的修改
  3. 传给前端的数据如果是一段html代码,可以通过.html('')的方法去渲染
  4. 绑定点击事件的时候尽量绑定大一点的div,不然绑定太小了怎么错的都不知道
  5. 重点区分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)
}
}
})
})

三、评论功能

总结注意点:

  1. 在一张表中有一个字段和表本身关联的时候,需要注意必须可以为空
  2. 有一些同时删除同时跟新的操作在没有外键关联的情况下可以使用事务
  3. 当我们在前端做一些对值的判断操作时,必须注意这个值是否需要清空

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项目☞点赞与评论的更多相关文章

  1. BBS项目分布搭建四(点赞点踩及评论功能准备)

    BBS项目分布搭建四(点赞点踩及评论功能) 1. 点赞点踩样式准备 # 在base.html文件中 head标签内 添加css模块: {% block css %} {% endblock %} # ...

  2. tornado web高级开发项目之抽屉官网的页面登陆验证、form验证、点赞、评论、文章分页处理、发送邮箱验证码、登陆验证码、注册、发布文章、上传图片

    本博文将一步步带领你实现抽屉官网的各种功能:包括登陆.注册.发送邮箱验证码.登陆验证码.页面登陆验证.发布文章.上传图片.form验证.点赞.评论.文章分页处理以及基于tornado的后端和ajax的 ...

  3. BBS项目分布搭建五(评论相关功能实现)

    BBS项目分布搭建五(评论相关) 1. 根评论逻辑实现 # 在models.py文件中 修改: # 7. 评论表 parent = models.ForeignKey(to='self', null= ...

  4. BBS论坛 文章详情、点赞、评论

    六.文章详情.点赞.评论 文章详情页面: def article_detail(request, username, article_id): # user_obj = models.UserInfo ...

  5. auth复习和BBS项目的登录(1)

    auth复习 auth组件 验证:authenticate(request,username='andy',password='123) 登录:login(request,user) 注销:login ...

  6. python 自动化之路 day 20 Django进阶/BBS项目【一】

    一.django进阶 1.django orm 增删改查 1.1.创建表: 1 2 3 >>> from blog.models import Blog >>> b ...

  7. day75 bbs项目☞后台管理+修改头像

    目录 一.后台管理之添加文章 二.修改用户头像 bbs项目总结 一.后台管理之添加文章 添加文章有两个需要注意的问题: 文章的简介切取,应该想办法获取到当前文章的文本内容后再截取字符 XSS攻击,由于 ...

  8. BBS项目(一)

    目录 BBS项目(一) 项目开发流程 BBS项目 BBS表分析 自关联 表关系图示 BBS项目(一) 项目开发流程 项目分类 针对互联网用户:抖音,淘宝····· 针对公司内部:后台管理系统··· 针 ...

  9. BBS项目(二)

    目录 BBS项目(二) ORM 创建相关表 表模型 修改admin样式 Simple-UI 注册表添加数据 注册forms类编写 注册功能前端搭建 头像实时显示功能实现 BBS项目(二) 可以在本地写 ...

随机推荐

  1. HDU-3033 I love sneakers! 题解

    题目大意 有 n 个物品,分成了 k 组,每个物品有体积和价值,把 n 个物品放到容量为 V 的背包中,保证每组至少放一件,求能获得的最大价值,如果不能实现,输出"Impossible&qu ...

  2. Communication【floyd判环+并查集】

    Communication 题目链接(点击) 题目描述 The Ministry of Communication has an extremely wonderful message system, ...

  3. RANK()的对比(SQL, Minitab, Excel)

    RANK()的对比(SQL, Minitab, Excel)也不是想来做什么对比的,只是顺便写此文,想学习一下Minitab的应用以便用它分析解决实际的问题. 回顾 May 23文章“开窗函数_ROW ...

  4. linux使用组ID(SGID)共享文件

    假如你有这样一个需求,一个小组内很多成员共同研究一个项目,为了这个项目我们需要分配一个具体的目录. 所有成员都拥有该目录的使用权限,可以互相操作成员的文件及内容.而且不允许其他人查看. 现在开始操作: ...

  5. log报错的原因解决

    idea未装lombok的插件: 1.用快捷键Ctrl+Alt+S打开:Settings→Plugins→Browse repositories 2.输入lom后选择Install,安装插件 3.按照 ...

  6. Zookeeper——分布式一致性协议及Zookeeper Leader选举原理

    文章目录 一.引言 二.从ACID到CAP/BASE 三.分布式一致性协议 1. 2PC和3PC 2PC 发起事务请求 事务提交/回滚 3PC canCommit preCommit doCommit ...

  7. 图像处理中的valid卷积与same卷积

    valid卷积 在full卷积的卷积过程中,会遇到\(K_{flip}\)靠近I的边界(K矩阵与I矩阵),就会有部分延申到I之外,这时候忽略边界,只考虑I完全覆盖\(K_{flip}\)内的值情况,这 ...

  8. Java Jar 包加密 -- XJar

    Java Jar 包加密 一.缘由 Java的 Jar包中的.class文件可以通过反汇编得到源码.这样一款应用的安全性就很难得到保证,别人只要得到你的应用,不需花费什么力气,就可以得到源码. 这时候 ...

  9. 006.OpenShift持久性存储

    一 持久存储 1.1 持久存储概述 默认情况下,运行容器使用容器内的临时存储.Pods由一个或多个容器组成,这些容器一起部署,共享相同的存储和其他资源,可以在任何时候创建.启动.停止或销毁.使用临时存 ...

  10. 【解读】Https协议

    一.为什么需要https 1.HTTP是明文传输的,也就意味着,介于发送端.接收端中间的任意节点都可以知道你们传输的内容是什么.这些节点可能是路由器.代理等. 举个最常见的例子,用户登陆.用户输入账号 ...