内容回顾
1. 个人博客主页
1. 分类展示
- 文章分类(2)
文章(Article)表和分类(Category)表
1. 先找这个人的博客有哪些文章分类
2. 每个文章分类下的文章总数
3. 基于对象的查询 category_obj.article_set.all().count()
- 文章标签
文章(Article)表和标签(Tag)表
1. 先找这个人的博客有哪些文章标签
2. 每个文章标签下的文章总数
3. 基于对象的查询 tag_obj.article_set.all().count()
- 日期归档
1. MySQL日期格式化函数 --> MySQL内置的那些函数
DATE_FORMAT(字段,'格式') --> sqlite语法:strftime('格式', '字段')
2. Django ORM执行原生SQL语句的方式:
1. .extra()
ret = models.Article.objects.all().extra(
select={"create_ym": "DATE_FORMAT(create_time, '%%Y-%%m-%%d')"}
)
# models.Article.objects.all() --> [ArticleObj1, ArticleObj2, ...]
# .extra(select={"create_ym": "DATE_FORMAT(create_time, '%%Y-%%m-%%d')"})
# --> ArticleObj1.create_ym
2. 类似pymysql的用法
# 更高灵活度的方式执行原生SQL语句
from django.db import connection # 连接
# 从连接中获取光标,等待输入命令
cursor = connection.cursor()
# 光标执行SQL语句
cursor.execute("""SELECT DATE_FORMAT(create_time, '%Y-%m') FROM blog_article;""")
# 取出SQL语句执行后的结果
ret = cursor.fetchall()
print(ret)
3. 使用ORM按照年月分组,分别统计出年月的的文章数
archive_list = models.Article.objects.filter(user=user_obj).extra(
select={"y_m": "DATE_FORMAT(create_time, '%%Y-%%m')"}
).values("y_m").annotate(c=Count("id")).values("y_m", "c")
2. 4合1路由实现分类访问文章
1. URL设计
注意事项:Django的urls.py中分组命名和分组匹配不能混合使用!!!
2. 视图中利用args去判断
3. 补充
1. QuerySet是惰性求值的
2. debug-tool-bar工具的使用:https://www.cnblogs.com/liwenzhou/p/9245507.html
今天我们实现文章的详情页面,就是当我们进入个人博客页面后,点击谋篇具体的文章,展示相应的文章详情。
我们就需要给文章详情配url,blog/yangbo/p/1,
所以a标签的地址就配成:
<a href="/blog/{{ user_obj.username }}/p/{{ article.id }} "><h4 class="media-heading">{{ article.title }}</h4></a>
url.py文件就配成:
url(r'^blog/(w+)/p/(d+)/$',views.article),
视图函数:
def article(request,username,id): ''' 文章详情页面 :param request: 请求对象 :param username:用户名 :param id:id :return: ''' user_obj = models.UserInfo.objects.filter(username=username).first() blog = user_obj.blog category_list = models.Category.objects.filter(blog=blog) tag_list = models.Tag.objects.filter(blog=blog) article_list = models.Article.objects.filter(user=user_obj) archive_list = models.Article.objects.filter(user=user_obj).extra( select={'y_m': 'DATE_FORMAT(create_time,"%%Y-%%m")'} ).values('y_m').annotate(c=Count('id')).values('y_m', 'c') article_obj = models.Article.objects.filter(id = id).first() print(article_obj.title) return render(request,'article.html',{ 'article_obj':article_obj, 'article_list': article_list, 'user_obj': user_obj, 'category_list': category_list, 'tag_list': tag_list, 'archive_list': archive_list })
这样我们发现页面有很多重复的代码:因为每个页面都基本一样只是文章展示区不一样,所以我们就想到了模板将一样的地方放在一个模板里。
新建一个html文件,将所有一样的代码放在base.html里,在模板页面中不一样的地方定义一个块
{% block page-main %}
{% endblock page-main %}
然后再子页面中:
{% extends 'base.html' %}
{% block page-main %}
写不一样的代码,这里的代码会替换base模板中block的内容。
{% endblock %}
在视图函数中,不管是在个人博客的视图函数还是在文章详情的试图函数中,我们都会看到很多重复的代码,首先我们想到的是把重复的代码写成一个函数,用这个函数的时候,调用就可以了,但是,如果这个函数除了问题,那么调用它的试图函数就不会执行页面就不会展示。这块有点难理解,可以复习一下模板和组件那块地内容!!!
这时候我们想到了组件:
在app的文件夹下创建一个名为templatetags(名字必须是templatetags)的package,在里面创建一个py文件,
在文件里必须写上这两行代码:
from django import template # 实例必须叫这个名字 register = template.Library()
然后再写组件的内容:
from django import template from blog import models from django.db.models import Count #实例必须叫这个名字 register = template.Library() @register.inclusion_tag(filename='left_menu.html') def left_con(username): print(username) user_obj = models.UserInfo.objects.filter(username=username).first() print(user_obj) blog = user_obj.blog category_list = models.Category.objects.filter(blog=blog) tag_list = models.Tag.objects.filter(blog=blog) archive_list = models.Article.objects.filter(user=user_obj).extra( select={'y_m': 'DATE_FORMAT(create_time,"%%Y-%%m")'} ).values('y_m').annotate(c=Count('id')).values('y_m', 'c') return { 'user_obj':user_obj, 'category_list': category_list, 'tag_list': tag_list, 'archive_list': archive_list }
bas.html页面中应该这样引入组件:
{% load left_memu %}
{% left_con user_obj.username %}
base.html中引入left_memu函数,并且将user_obj.username传给这个left_con函数,left_con将返回值传给left_menu.html页面渲染,渲染完了之后,然后在把整个left_menu.html页面在base.html页面中渲染。
接下来就是给文章详情添加点赞的功能:
当我们点击点赞或反对时 ,我们应该拿到的是文章的id,和用户名的id,然后把这些数据传给后端,后端在数据库中做记录,然后将数据在页面中渲染。
html代码:
<!--点赞开始--> <div id="div_digg"> <div class="diggit digg"> <span class="diggnum" id="digg_count">{{ article_obj.up_count }}</span> </div> <div class="buryit digg"> <span class="burynum" id="bury_count">{{ article_obj.down_count }}</span> </div> <div class="clear"></div> <!--提示信息--> <div class="diggword" id="digg_tips"> </div> </div> <!--点赞结束-->
$('.digg').click(function () { if(!'{{ request.user.username }}'){ //如果不加引号,就会被当成是变量 //先判断有没有登陆,没有登陆就跳转到登陆页面 location.href = '/login/?next={{ request.get_full_path }}' } //已经登陆就可以点赞或反对 var userid = '{{ request.user.id }}'; var articleid = '{{ article_obj.id }}'; //区分点赞还是反对 var isup = $(this).hasClass('diggit'); // 像后端发请求 $.ajax({ url:'/up_down/', type:'post', data:{ csrfmiddlewaretoken:$('[name="csrfmiddlewaretoken"]').val(), userid:userid, articleid:articleid, isup:isup, }, success:function (res) { if(res.code!==0){ //只需要把错误提示显示出来就可以 $('.diggword').text(res.msg) }else{ //1.更新点赞数或反对数 if(isup){ //点赞数加一 var $UpSpan = $("#digg_count"); $UpSpan.text(+$UpSpan.text()+1); $('.diggword').text(res.msg) }else{ // 反对数加一 var $downSpan = $("#bury_count"); $downSpan.text(+$downSpan.text()+1); // 打印提示信息 $('.diggword').text(res.msg) } } } }) });
views代码:
def up_down(request): if request.method == 'POST': print(request.POST) res={'code':0} userid = request.POST.get('userid') articleid = request.POST.get('articleid') isup = request.POST.get('isup') isup = True if isup.upper() == 'TRUE' else False # 5. 不能给自己点赞 is_own_article= models.Article.objects.filter(user_id=userid,id=articleid).first() print(is_own_article) if is_own_article: res['code'] = 1 res['msg'] = '不能给自己点赞或反对' else: # 3.同一个人只能给同一篇文章点赞一次 # 4. 点赞和反对两个只能选一个 # 判断一下 当前这个人和这篇文章在点赞表里有没有记录 is_exit = models.ArticleUpDown.objects.filter(user_id=userid,article_id=articleid).first() # 如果存在 if is_exit: res['code'] = 1 # 表示已经点赞过 if is_exit.is_up == True: res['msg'] = '已经点赞过了' # 表示已经反对过 else: res['msg'] = '已经反对过了' else: from django.db import transaction from django.db.models import Count, F # 事务操作 with transaction.atomic(): # 1.先创建点赞记录 models.ArticleUpDown.objects.create(user_id=userid,article_id=articleid,is_up=isup) # 2.在更新文章表 if isup: # 点赞数加1 models.Article.objects.filter(id=articleid).update(up_count=F('up_count')+1) res['msg'] = '点赞成功' else: #反对数加1 models.Article.objects.filter(id=articleid).update(down_count=F('down_count')+1) res['msg'] = '反对成功' return JsonResponse(res)