侧边栏筛选
后端
def category(request, username, category_id):
user = UserInfo.objects.filter(username=username).first()
if user:
category_name = Category.objects.filter(pk=category_id).first().name
article_list = Article.objects.filter(blog_id=user.blog.id).all().filter(category_id=category_id)
res_category = Article.objects.filter(blog=user.blog).values('category_id').annotate(
article_count=Count('id')).values(
'category__id', 'category__name', 'article_count')
res_tag = Article.objects.filter(blog=user.blog).values('tag__id').annotate(article_count=Count('id')).values(
'tag__id', 'tag__name', 'article_count')
res_date = Article.objects.filter(blog=user.blog).annotate(create_date=TruncMonth('create_time')).values(
'create_date').annotate(article_count=Count('id')).values('create_date', 'article_count')
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
def tag(request, username, tag_id):
user = UserInfo.objects.filter(username=username).first()
if user:
tag_name = Tag.objects.filter(pk=tag_id).first().name
article_list = Article.objects.filter(blog_id=user.blog.id).all().filter(tag__id=tag_id)
res_category = Article.objects.filter(blog=user.blog).values('category_id').annotate(
article_count=Count('id')).values(
'category__id', 'category__name', 'article_count')
res_tag = Article.objects.filter(blog=user.blog).values('tag__id').annotate(article_count=Count('id')).values(
'tag__id', 'tag__name', 'article_count')
res_date = Article.objects.filter(blog=user.blog).annotate(create_date=TruncMonth('create_time')).values(
'create_date').annotate(article_count=Count('id')).values('create_date', 'article_count')
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
def date_articel(request, username, date_y_m):
user = UserInfo.objects.filter(username=username).first()
if user:
# 2023-11
year, month = date_y_m.split('-')
article_list = Article.objects.filter(blog_id=user.blog.id).all().filter(create_time__year=year,
create_time__month=month)
res_category = Article.objects.filter(blog=user.blog).values('category_id').annotate(
article_count=Count('id')).values(
'category__id', 'category__name', 'article_count')
res_tag = Article.objects.filter(blog=user.blog).values('tag__id').annotate(article_count=Count('id')).values(
'tag__id', 'tag__name', 'article_count')
res_date = Article.objects.filter(blog=user.blog).annotate(create_date=TruncMonth('create_time')).values(
'create_date').annotate(article_count=Count('id')).values('create_date', 'article_count')
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
路由
path('<str:username>/category/<int:category_id>.html', views.category),
path('<str:username>/tag/<int:tag_id>.html', views.tag),
# 2023-11
path('<str:username>/archive/<str:date_y_m>.html', views.date_articel),
前端
{% block left %}
<div class="panel panel-primary">
<div class="panel-heading"><h3 class="panel-title">我的标签</h3></div>
<div class="panel-body">
{% for tag in res_tag %}
<p><a href="/{{ user.username }}/tag/{{ tag.tag__id }}.html">{{ tag.tag__name }}({{ tag.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">随笔分类</h3></div>
<div class="panel-body">
{% for category in res_category %}
<p>
<a href="/{{ user.username }}/category/{{ category.category__id }}.html">{{ category.category__name }}({{ category.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading"><h3 class="panel-title">随笔档案</h3></div>
<div class="panel-body">
{% for item in res_date %}
<p>
<a href="/{{ user.username }}/archive/{{ item.create_date|date:'Y-m' }}.html">{{ item.create_date|date:'Y年m月' }}({{ item.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}</div>
</div>
{% endblock %}
侧边栏抽取
1.1 三个路由合三为一
# 3个路由合为一个
# path('<str:username>/category/<int:category_id>.html', views.site),
# path('<str:username>/tag/<int:tag_id>.html', views.site),
# path('<str:username>/archive/<str:date_y_m>.html', views.site),
# 为一个
#/lqz/archive/2023-11.html --->username=lqz choice=archive condition=2023-11
# /lqz/tag/1.html--------> username=lqz choice=tag condition=1
#/lqz/category/3.html----> username=lqz choice=category condition=3
re_path('(?P<username>\w+)/(?P<choice>category|tag|archive)/(?P<condition>.*?).html', views.site),
# 个人站点路由放最后---》上面所有都匹配完了--->再看是不是个人站点
path('<str:username>', views.site),
四个视图函数合四为一
def site(request, username, **kwargs): # 以上三种都能接收
user = UserInfo.objects.filter(username=username).first()
if user:
article_list = Article.objects.filter(blog_id=user.blog.id).all()
choice = kwargs.get('choice', None)
condition = kwargs.get('condition', None) # 如果 choice 有值,condition一定有
if choice and choice == 'category': # choice有值 说明不是个人站点的:可能是 tag筛选,标签筛选,日期筛选,并且choice是 category,按标签过滤的
category_name = Category.objects.filter(pk=condition).first().name
article_list = article_list.filter(category_id=condition)
elif choice and choice == 'tag':
tag_name = Tag.objects.filter(pk=condition).first().name
article_list = article_list.filter(tag__id=condition)
elif choice and choice == 'archive':
date_y_m=condition
year, month = condition.split('-')
article_list = article_list.filter(create_time__year=year, create_time__month=month)
res_category = Article.objects.filter(blog=user.blog).values('category_id').annotate(
article_count=Count('id')).values('category__id', 'category__name', 'article_count')
res_tag = Article.objects.filter(blog=user.blog).values('tag__id').annotate(article_count=Count('id')).values(
'tag__id', 'tag__name', 'article_count')
res_date = Article.objects.filter(blog=user.blog).annotate(create_date=TruncMonth('create_time')).values(
'create_date').annotate(article_count=Count('id')).values('create_date', 'article_count')
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
侧边栏抽取
之前学过 include---》固定的,不能动态变化
# inclusion_tag---》返回一个动态的html片段---》编写方式类似于标签和过滤器
# 编写步骤
1、在settings中的INSTALLED_APPS配置当前app,不然django无法找到自定义的simple_tag.
2、在app中创建templatetags模块(模块名只能是templatetags)
3、创建任意 .py 文件,如:my_tags.py
4、导入,实例化得到对象 register的名字是固定的,不可改变
from django import template
register = template.Library()
5、使用装饰器
@register.inclusion_tag('left.html', name='left')
def left(username):
user = UserInfo.objects.filter(username=username).first()
res_category = Article.objects.filter(blog=user.blog).values('category_id').annotate(
article_count=Count('id')).values('category__id', 'category__name', 'article_count')
res_tag = Article.objects.filter(blog=user.blog).values('tag__id').annotate(article_count=Count('id')).values(
'tag__id', 'tag__name', 'article_count')
res_date = Article.objects.filter(blog=user.blog).annotate(create_date=TruncMonth('create_time')).values(
'create_date').annotate(article_count=Count('id')).values('create_date', 'article_count')
return {'user': user, 'res_category': res_category, 'res_tag': res_tag, 'res_date': res_date}
6、html片段
<div>
<div class="panel panel-primary">
<div class="panel-heading"><h3 class="panel-title">我的标签</h3></div>
<div class="panel-body">
{% for tag in res_tag %}
<p><a href="/{{ user.username }}/tag/{{ tag.tag__id }}.html">{{ tag.tag__name }}({{ tag.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}
</div>
</div>
<div class="panel panel-info">
<div class="panel-heading"><h3 class="panel-title">随笔分类</h3></div>
<div class="panel-body">
{% for category in res_category %}
<p>
<a href="/{{ user.username }}/category/{{ category.category__id }}.html">{{ category.category__name }}({{ category.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading"><h3 class="panel-title">随笔档案</h3></div>
<div class="panel-body">
{% for item in res_date %}
<p>
<a href="/{{ user.username }}/archive/{{ item.create_date|date:'Y-m' }}.html">{{ item.create_date|date:'Y年m月' }}({{ item.article_count }})</a>
</p>
{% if not forloop.last %}
<hr>
{% endif %}
{% endfor %}</div>
</div>
</div>
7、在模板中使用
{% load common_left %}
{% left username%}
文章页面
后台
def article_detai(request, username, article_id):
article = Article.objects.filter(pk=article_id).first()
return render(request, 'article_detail.html', locals())
前台
{% extends 'base.html' %}
{% block title %}
{{ article.title }}
{% endblock %}
{% block site_name %}
{{ article.blog.site_name }}
{% endblock %}
{% block content %}
<h2 class="text-center">{{ article.title }}</h2>
<hr>
{{ article.content|safe }}
{% endblock %}
文章点赞
后端
import json
# 加装饰器,只能实现,进不到这个函数中执行,无法定制返回给ajax的数据---》前端不好操作
def upanddown(request):
# 当前登录用户,如果取不出来,需要返回让它登录
user = request.user
if user.is_authenticated:
# 判断是点赞还是点踩
article_id = request.POST.get('article_id')
up_or_down = request.POST.get('up') # 是字符串类型,转成 布尔
up_or_down = json.loads(up_or_down)
res = UpAndDown.objects.filter(article_id=article_id, user=user).first()
if res:
return JsonResponse({'code': 102, 'msg': '您已经点过了'})
else:
######## 在一个视图函数中,操作了两个表---》这两个操作属于:同一个事务#####
# 存点赞点踩表
UpAndDown.objects.create(user=user, article_id=article_id, is_up=up_or_down)
# 让文章的点赞或点踩加1
if up_or_down:
Article.objects.filter(pk=article_id).update(up_number=F('up_number') + 1)
return JsonResponse({'code': 100, 'msg': '点赞成功'})
else:
Article.objects.filter(pk=article_id).update(down_number=F('down_number') + 1)
return JsonResponse({'code': 100, 'msg': '点踩成功'})
else:
return JsonResponse({'code': 101, 'msg': '您没有登录,请先 <a href="/login/" style="color: red">登录</a>'})
前端
{% extends 'base.html' %}
{% block title %}
{{ article.title }}
{% endblock %}
{% block header %}
<link rel="stylesheet" href="/static/css/common_css.css">
{% endblock %}
{% block site_name %}
{{ article.blog.site_name }}
{% endblock %}
{% block content %}
<h2 class="text-center" article_id="{{ article.id }}">{{ article.title }}</h2>
<hr>
{{ article.content|safe }}
<hr>
<div id="div_digg">
<div class="diggit digg">
<span class="diggnum" id="digg_count">{{ article.up_number }}</span>
</div>
<div class="buryit digg">
<span class="burynum" id="bury_count">{{ article.down_number }}</span>
</div>
<div class="clear"></div>
<div class="diggword" id="digg_tips">
</div>
</div>
{% endblock %}
{% block script %}
<script>
// 笨办法,给点赞绑定一个事件,给点踩绑定一个事件---》分别提交
$('.digg').click(function () {
// 判断,如果点的div 有diggit类就是点赞
var up = $(this).hasClass('diggit')
console.log($('h2').attr('article_id'))
let _this = this
//发送ajax请求
$.ajax({
url: '/upanddown/',
method: 'post',
data: { //谁(当前登录用户)对那篇文章(文章id)点赞或点踩(up)
article_id: '{{ article.id }}',
//article_id: $('h2').attr('article_id'),
up: up,
csrfmiddlewaretoken: '{{ csrf_token }}'
},
success: function (data) {
console.log(data)
$('#digg_tips').html(data.msg)
if (data.code == 100) {
// 让数字加1 赞+1 踩 +1
var num = Number($(_this).children('span').html())
$(_this).children('span').html(num + 1)
}
}
})
})
</script>
{% endblock %}