一、内容回顾
# 1 登录页面搭建
-bootsrtap的栅格,form-group, input:form-control
-验证码
# 2 验证码图片的生成
-1 pillow生成一张图片
-2 图片上写文字
-3 设置文字大小,设置文字颜色,设置文字字体格式(ttf)
-4 5位大小写字母,数字
-5 点,线,弧形
-6 放到bytesio,取出来
img.save(f,'png')
f.getvalue()
-7 返回给前端 HttpResponse
JsonResponse({code:100,data:asdfasdfasdfasd})
"""
HttpResponse主要用于直接返回字符串类型的数据
JsonResponse只能返回字典或者列表,而且你想返回列表的话,需要加参数 safe=True
JsonResponse也可以将文件转换以后的数据以二进制的方式存储在kv键值对中
JsonResponse({code:100,data:asdfasdfasdfasd})
"""
# 3 登录后台
-取出用户名,密码,验证码
-从session中取出验证码,判断传入的是否一致
-使用它:authenticate 验证用户名密码是否正确 ---》密码是加密的
-django内置user表的密码加密:虽然密码一致,但是生成的加密后的串是不一样的
"""
我们也想自己的密码被加密,我们就可以点开UserInfo.objects.create_user(**register_data)的源代码
发现主要是user.password = make_password(password)在起作用
from django.contrib.auth.hashers import make_password
秘文=make_password('明文')
"""
from django.contrib.auth import authenticate, login as auth_login, logout
auth_login(request,user)
"""
登录成功之后使用auth_login(request,user)记录登录成功以后的状态
"""
二、首页渲染(文章的摘要方面)
<a href="#">
<img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}" alt="..." height="50px" width="50px">
</a>
"""
settings的media地址MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
以后再上传的文件是从media文件夹下面开始的,原来就有的默认在static文件夹下!!!!!!!!
model中avatar = models.FileField(upload_to='avatar', default='avatar/default.png')自动存储到media/avatar
urls中开启media文件访问权限path('media/<path:path>', serve, {'document_root': settings.MEDIA_ROOT}),
"""
{{ article.upanddown_set.all.count}}
"""
这里是在前端显示点赞和点踩数,注意这样写每加载一次页面就会访问一次数据库,数据库压力过大
解决方法为直接在article表中加入字段,下面只写新加入的字段
"""
class Article(models.Model):
up_num = models.IntegerField(default=0)
down_num = models.IntegerField(default=0)
comment_num = models.IntegerField(default=0)
"""
直接在article中写字段能有效降低访问量
"""
# auth_user的迁移migrate必须在扩写之后完成!!!!!!!!!!!!!!!!!!!!!!
不然想改的话需要先去删库,再去删除迁移记录(admin的,auth的)
先去view里面找源码,之后按左上角的瞄准镜进入文件所在位置,删除migrations文件夹下的迁移记录(文件夹本身以及__init__不能删 )
之后在同一目录的auth中的migrations文件夹文件夹下执行统一操作
{{ article.create_time|date:'Y-m-d H:s'}}data过滤器
三、个人站点页面搭建
文字描述为上面一个边框,左边一个标签导航条,右边都是文章的摘要
首先要开一个路由,该路由的目的是接收作者名字信息,之后跳转到作者的页面所以路由为
path('<str:name>', views.site)
————————————————————————————————————————————————
def site(request, name):
user = models.UserInfo.objects.filter(username=name).first()
article_list = models.Article.objects.all().filter(blog=user.blog)
article_list = user.blog.article_set.all()
if user:
return render(request, 'site.html', {'article_list':article_list})
return render(request, '404.html')
"""
1.注意这个路由必须写在最下面,不然会使得其他路由失效
2.我们注意这里需要展示的是这个作者下面的文章
3.article_list = models.Article.objects.all().filter(blog=user.blog)
4.上面的filter使用方式挺重要的,其他地方也可以使用!!!!!!!!!!!!!!!!!!!!!
"""
四、个人站点左侧渲染(重要!!!!!!!!!!!!!!!!!!!!!!!!!!!)
我们的目标要统计这个人的每个分类下的所有文章
1.首先我们用sql
select blog_category.id,blog_category.name,count(blog_article.id), blog_category.blog_id from blog_category left join blog_article on blog_category.id = blog_article.category_id where blog_category.blog_id = 1 group by blog_category.id
"""
1.where的筛选必须在group by分组前面执行
2.首先进行并表操作
select * from blog_category left join blog_article on blog_category.id = blog_article.category_id
3.之后进行分组,确定分组依据,利用count计数
select blog_category.id,blog_category.name,count(blog_article.id), blog_category.blog_id from blog_category left join blog_article on blog_category.id = blog_article.category_id group by blog_category.id
4.最后用where加上查询条件注意where的位置!!!!!!!!!!!!!!!!!!!!!!!!!
"""
2.之后是django的查询方法(正反向查询)
category_res = models.Category.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
category_res1 = models.Article.objects.filter(blog=user.blog).values('category_id').annotate(c=Count('id')).values_list('category_id', 'category__name', 'c')
"""
1.首先进行并表操作annotate可以理解为指定合并的表格,Count用来计算分组数据
models.Category.objects.annotate(c=Count('article__id'))
2.value在前作用是指定分组的依据依照Category的id进行分组
models.Article.objects.values('category_id').annotate(c=Count('id'))
3.之后自己指定需要哪些字段
models.Category.objects.values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
4.最后再自己去加筛选条件和上面的where同理虽然是最后写的,位置却不能错
models.Article.objects.filter(blog=user.blog).values('category_id').annotate(c=Count('id')).values_list('category_id', 'category__name', 'c')
5.因为都是合并以后去查,所以是可以有两个写法的
"""
tag_res = models.Tag.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
tag_res1 = models.Article.objects.filter(blog=user.blog).values('tag__id').annotate(c=Count('id')).values_list('tag__id', 'tag__name', 'c')
# 这里的标签也是同上
# 原生sql转成orm
filter 在annotate前,表示where 条件
valeus 在annotate前,表示分组依据(group by 谁里面就写谁)
filter 在annotate后,表示having 条件
valeus 在annotate后,表示取字段 (id ,name ,c)
where与having的功能其实是一样的 都是用来筛选数据
只不过where用于分组之前的筛选 而having用于分组之后的筛选
为了人为的区分 所以叫where是筛选 having是过滤
select post,avg(salary) from emp where age>30 group by post having avg(salary) > 10000;
# 随笔档案的查询数据结构
-分组,单表 文章表---发布时间(年月日十分秒)
-文章表的数据,在单表中增加一个year_month字段,以它作为分组依据
id title create_time year_month
1 go 2022年9月18日 10时23分14秒 2022年9月
3 java 2022年9月14日 10时23分14秒 2022年9月
2 python 2022年7月10日 10时23分14秒 2022年7月
4 js 2022年8月12日 10时23分14秒 2022年8月
'''
Sales.objects.all().
.annotate(year_month=TruncMonth('create_time')) # Truncate to month and add to select list
.values('year_month') # Group By year_month
.annotate(c=Count('id')) # Select the count of the grouping
.values('year_month', 'c') # (might be redundant, haven't tested) select month and count
'''
五、个人站点左侧响应点击事件
当前的地址为 http://127.0.0.1:8000/jason
<a href="{{ user.username }}/tag/{{ tag.0 }}.html">
<a href="/{{ user.username }}/tag/{{ tag.0 }}.html">
"""
注意!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
第一种发送的地址为http://127.0.0.1:8000/jason/jason。。。。。。。。。
第一种发送的地址为http://127.0.0.1:8000/jason。。。。。。。
有斜杠的表示从根路径开始添加,没有用斜杠的则是从当前路径开始添加
"""
<a href="/{{ user.username }}/achieve/{{ data.0|date:'Y/m' }}">
path('<str:name>/archive/<int:year>/<int:month>.html', views.site)
# 因为上面的内容当中有Y/m,下面就得多个接收器
urlpatterns = [
path('<str:name>', views.site),
path('<str:name>/tag/<int:tag>.html',views.site),
path('<str:name>/category/<int:category>.html',views.site),
path('<str:name>/achieve/<int:year>/<int:month>.html', views.site),
]
——————————————————————————————————————————————————
<a href="/{{ user.username }}/tag/{{ tag.0 }}.html">
<a href="/{{ user.username }}/category/{{ category.0 }}.html">
<a href="/{{ user.username }}/achieve/{{ data.0|date:'Y/m' }}.html">
——————————————————————————————————————————————————
def site(request,name, **kwargs):
user = models.UserInfo.objects.filter(username=name).first()
if user:
article_list = models.Article.objects.all().filter(blog=user.blog)
tag = kwargs.get('tag')
category = kwargs.get('category')
year = kwargs.get('year')
month = kwargs.get('month')
if tag:
article_list = article_list.filter(tag__id=tag)
elif category:
article_list = article_list.filter(category__id=category)
elif year and month:
article_list = article_list.filter(create_time__year=year,create_time__month=month)
tag_res = models.Tag.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
category_res = models.Category.objects.filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list('id', 'name', 'c')
data_res = models.Article.objects.filter(blog=user.blog).annotate(year_month=TruncMonth('create_time')).values('year_month').annotate(c=Count('id')).values_list('year_month', 'c')
print(data_res)
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
"""
这里做到了使用一个函数去接收传过来的参数巧妙的使用了**kwargs接收多余的参数
article_list = article_list.filter(create_time__year=year,create_time__month=month)这里是获取年月的方式以前好像没见过!!!!!!!!!!!!!
"""
五、路由最简化版本
re_path('^(?P<name>\w+)/(?P<type_name>tag|category|archive)/(?P<condition>\d+).html', views.site),
————————————————————————————————————————————————
def site(request, name, **kwargs):
# 根据人名查到数据库中,才返回个人站点,如果没有,返回404页面
user = UserInfo.objects.filter(username=name).first()
if user:
# 返回当前这个人所有文章
article_list = Article.objects.all().filter(blog=user.blog)
# 要么根据tag,category或时间过滤
type_name = kwargs.get('type_name')
condition = kwargs.get('condition')
if type_name == 'tag':
article_list = article_list.filter(tag__id=condition) # 跨表到tag表,过滤tag的id为传入的id号
elif type_name == 'category':
article_list = article_list.filter(category_id=condition) # 跨表到tag表,过滤tag的id为传入的id号
elif type_name == 'archive':
year = str(condition)[:4]
month = str(condition)[4:]
article_list = article_list.filter(create_time__year=year, create_time__month=month)
category_res = Category.objects.all().filter(blog=user.blog).values('id').annotate(
c=Count('article__id')).values_list('id', 'name', 'c')
tag_res = Tag.objects.all().filter(blog=user.blog).values('id').annotate(c=Count('article__id')).values_list(
'id', 'name', 'c')
date_res = Article.objects.all().filter(blog=user.blog).annotate(year_month=TruncMonth('create_time')).values(
'year_month').annotate(c=Count('id')).values_list('year_month', 'c')
print(tag_res)
print(category_res)
print(date_res)
return render(request, 'site.html', locals())
else:
return render(request, '404.html')
"""
1.这里使用了正则表达式同时能够接受三种地址
2.这里最骚的是把日期转化为20220212这种数字的格式就不用新开路由了
"""