day74-BBS-文章的详情页、点赞点踩、评论等功能

每日测验

"""
今日考题
1.django admin作用及用法
2.media配置如何实现,基于该配置能够做到什么以及需要注意什么
3.阐述博客园为何支持用户自定义个人站点样式,内部可以如何实现
4.阐述侧边栏展示及筛选功能具体业务逻辑
"""

内容回顾

  • 登陆功能后端实现

    # 前后端基于ajax交互的话 那么后端通常会返回字典格式数据
    """
    1.验证码判断是否正确
    	忽略大小写
    """
    
  • 首页搭建

    # django admin后台管理
    """
    urls.py自带的那个url
    
    特点:
    	能够自动生成注册了的模型表的增删改查四条url及相应的界面
    
    使用
    	在对应的应用下的admin.py文件中注册模型表即可
    	admin.site.register(models.UserInfo)
    	...
    class UserInfo(models.Model):
    	username = models.CharField(verbose_name='字段名')
    	class Meta:
    		verbose_name_plural = '表名'
    
    针对bbs在绑定数据的时候一定要细心
    	1.先去文章表里面绑定数据
    	2.个人站点
    	3.文章分类
    	4.将用户和个人站点绑定关系
    	5.文章与文章标签
    
    
    
  • media配置

    """
    网址所使用到的静态资源默认都是放在static文件夹下
    用户上传的静态文件资源也应该单独找个位置存放
    
    media配置
    	settings.py
    		MEDIA_ROOT = os.path.join(BASE_DIR,'media')
    用户上传文件会自动创建media文件夹然后在该文件夹内存储数据
    """
    
  • 如何自定义暴露后端资源

    # 你需要自己在urls.py中书写代码
    from django.views.static import serve
    from BBS14 import settings
    
    # 固定写法 不要自己改动
    url(r'^media/(?P<path>.*)',serve,{
          
          'document_root':settings.MEDIA_ROOT}),
    
  • 个人站点

    # 由于url方法第一个参数是正则表达式,所有当路由特别多的时候,可能会出现被顶替的情况,针对这种情况有两种解决方式
    	1.修改正则表达式
      2.调整url方法的位置
    
    """
    1.页面布局不再是282 变成左右布局
    2.个人站点每个人的样式都不一样内部大致如何实现的
    	内部给每个人开设了可以自定义css和js的文件接口并且用户自定义之后会将用户的文件保存下来,之后在打开用户界面的时候会自动加载用户自己写的css和js从而实现每个用户界面不一样的情况
    3.侧边栏展示问题
    	只要你的orm学的没有问题一般情况下不会有难度
    	只要是queryset对象就可以无限制的点击queryset对象方法
    		filter().filter().filter().filter()
    	
    	# 1 查询当前用户所有的分类及分类下的文章数
    	# 2 查询当前用户所有的标签及标签下的文章数
    	# 3 按照年月统计所有的文章
    		1.需要截取日期字段
    			参考官网提供的方法
    				from django.db.models.functions import TruncMonth
    				date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(count_num=Count('pk')).values_list('month','count_num')
    	
    		2.如果按照上述写法出现报错,那么需要你去配置文件中修改时区
    		TIME_ZONE = 'Asia/Shanghai'
    		USE_TZ = False
    4.侧边栏筛选功能
    	1.多个url公用一个视图函数
    	2.当多个url公用一个视图函数的时候 你应该思考着多个url能不能优化一下
    		# 个人站点页面搭建
        url(r'^(?P<username>\w+)/$',views.site,name='site'),
        # 侧边栏筛选功能
        # url(r'^(?P<username>\w+)/category/(\d+)/',views.site),
        # url(r'^(?P<username>\w+)/tag/(\d+)/',views.site),
        # url(r'^(?P<username>\w+)/archive/(\w+)/',views.site),
        # 上面的三条url其实可以合并成一条
        url(r'^(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)/',views.site)
    	
    	
    	    if kwargs:
            # print(kwargs)  # {'condition': 'tag', 'param': '1'}
            condition = kwargs.get('condition')
            param = kwargs.get('param')
            # 判断用户到底想按照哪个条件筛选数据
            if condition == 'category':
                article_list = article_list.filter(category_id=param)
            elif condition == 'tag':
                article_list = article_list.filter(tags__id=param)
            else:
                year,month = param.split('-')  # 2020-11  [2020,11]
                article_list = article_list.filter(create_time__year=year,create_time__month=month)
    
    5.手动补全侧边栏url即可
    """
    

今日内容概要

ps:今日内容比较繁琐(逻辑和代码量稍微多了一点)

  • 侧边栏制作成inclusion_tag
  • 文章的点赞点踩(重点)
  • 文章的评论(重点)
    • 先只做根评论
    • 之后再做子评论
    • 小bug完善

扩展:admin路由分发的本质

# 路由分发本质    include  可以无限制的嵌套N多层
 url(r'^index/',([],None,None))
	
  # url(r'^index/',([
  #         url(r'^index_1/',([
  #                 url(r'^index_1_1',index),
  #                 url(r'^index_1_2',index),
  #                 url(r'^index_1_3',index),
  #                           ],None,None)),
  #         url(r'^index_2/',index),
  #         url(r'^index_3/',index),
  #                 ],None,None)),

“”"

文章详情页

# 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
@register.inclusion_tag('left_menu.html')
def left_menu(username):
    # 构造侧边栏需要的数据
    user_obj = models.UserInfo.objects.filter(username=username).first()
    blog = user_obj.blog
    # 1 查询当前用户所有的分类及分类下的文章数
    category_list = models.Category.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values_list(
        'name', 'count_num', 'pk')
    # print(category_list)  # <QuerySet [('jason的分类一', 2), ('jason的分类二', 1), ('jason的分类三', 1)]>

    # 2 查询当前用户所有的标签及标签下的文章数
    tag_list = models.Tag.objects.filter(blog=blog).annotate(count_num=Count('article__pk')).values_list('name',
                                                                                                         'count_num',
                                                                                                         'pk')
    # print(tag_list)  # <QuerySet [('tank的标签一', 1), ('tank的标签二', 1), ('tank的标签三', 2)]>

    # 3 按照年月统计所有的文章
    date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values(
        'month').annotate(count_num=Count('pk')).values_list('month', 'count_num')
    # print(date_list)
    return locals()

文章点赞点踩

"""
浏览器上你看到的花里胡哨的页面,内部都是HTML(前端)代码

那现在我们的文章内容应该写什么???	>>> html代码

如何拷贝文章
	copy outerhtml

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

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

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

"""
# 个人建议:写代码先把所有正确的逻辑写完再去考虑错误的逻辑 不要试图两者兼得
import json
from django.db.models import F
def up_or_down(request):
    """
    1.校验用户是否登陆
    2.判断当前文章是否是当前用户自己写的(自己不能点自己的文章)
    3.当前用户是否已经给当前文章点过了
    4.操作数据库了
    :param request:
    :return:
    """
    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')
            # print(is_up,type(is_up))  # true <class 'str'>
            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)

<script>
        //   给所有的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)
                        }
                }
            })
        })
    </script>

文章评论

"""
我们先写根评论
再写子评论

点击评论按钮需要将评论框里面的内容清空

根评论有两步渲染方式
	1.DOM临时渲染
	2.页面刷新render渲染

子评论
	点击回复按钮发生了几件事
		1.评论框自动聚焦
		2.将回复按钮所在的那一行评论人的姓名
			@username
		3.评论框内部自动换行
	
根评论子评论都是点击一个按钮朝后端提交数据的
	parent_id
根评论子评论区别在哪?
	parent_id
"""

猜你喜欢

转载自blog.csdn.net/zdw20190510/article/details/113616667