内容回顾
-
登陆功能后端实现
# 前后端基于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.文章与文章标签 扩展: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)), """
-
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完善
文章详情页
# 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 """