目录
昨日内容
昨日内容回顾
登录功能
图片验证码
自己写的
pillow模块
图片相关的它都可以操作
图片上写字
图片上加虚幻效果
加一些妨碍你观看的对象
登录功能逻辑
pillow模块
生成图片
画笔
字体
.ttf结尾的都是用来控制字体样式
io模块
内存管理器
ByteIo StringIo
chr() 数字转字母
ord() 字母转数字
random模型
def get_code(n):
code = ''
for i in range(n):
upper_str = chr(random.randint(65,90))
lower_str = chr(random.randint(97,122))
random_int = str(random.randint(0,9))
code += random.choice([upper_str,lower_str,random_int])
return code
我们是将产生的随机验证码保存到了session中(session有时候可以作为临时存储数据的仓库
并不一定非要是和用户登录相关的业务才能操作session
)
前端点击图片自动刷新
利用的src后面的url变化就会自动再次朝该url发送get请求
首页搭建
282布局
跟对一个好的领导
导航条用户功能
1.根据用户是否登录 来控制导航条左侧显示的内容
用户登录 显示用户名和更多操作
用户没有登录 显示登录注册
利用request.user.is_authenticated()
2.修改密码
check_password
set_password
save()
只要是跟用户相关的功能 你都利用auth模块来帮你简单快捷的实现
在以后的工作中 任何不要想着立马自己动手写
一定要先想有没有相应的模块
先按照自己的思路先往下写 写到没法实现的地方
可以寻求相应的模块
3.退出登录
logout()
django admin后台管理
Xadmin组件
本身有很多bug
使用
-
去应用下的admin.py中注册你想要管理的模型类
from app01 import models admin.site.register(models.Userinfo)
admin.site.register(models.Blog)
admin.site.register(models.Tag)
admin.site.register(models.Category)
admin.site.register(models.Article)
admin.site.register(models.Article2Tag)
admin.site.register(models.UpAndDown)
admin.site.register(models.Comment) -
要想登录到后台管理,必须是超级用户,管理员root权限
createsuperuser
-
admin会自动给所有的注册了的模型表加一个s后缀
-
admin会自动给注册了的模型表自动生成增删改查四条url
url(r'^admin/', admin.site.urls) http://127.0.0.1:8000/admin/app01/userinfo/ 查
http://127.0.0.1:8000/admin/app01/userinfo/3/change/ 改
http://127.0.0.1:8000/admin/app01/userinfo/3/delete/ 删
http://127.0.0.1:8000/admin/app01/userinfo/add/ 增 -
更换后台中表的中文显示
在模型表中models.py
在表名类下定义类:
class Meta:
verbose_name_plural = '用户表' // 直接更改 # verbose_name = '用户表 // 自动加s后缀 -
查看时显示第三张表中的文件显示
# 表类中定义双下str方法,便于查看
def __str__(self):
return self.username
建表
首先录入Article表数据,表中外键字段较多,但可以通过点击的方式跳转到外键关联的表中
-
建立userinfo表的外键字段表关系,用于确认用户与个人站点之间的外键关联
- 在添加前使表关系中的phone字段添加
blank=true
属性,告诉admin后台管理该字段可以为空
- 在添加前使表关系中的phone字段添加
Tag表绑定标签
文章与标签的多对多关系,在第三张表中绑定关系
编写前端数据显示
用户图片的显示
前端for循环进行查看图片时加载不出来
- 网站所用到的静态文件统一默认都放在static文件夹内
- 用户上传的静态文件也应该单独找一个文件夹存储
- 无论用户上传什么类型的文件,只要是静态的都应该放在某一个固定的文件夹下
MEDIA用户配置
media配置,能够将用户上传的所有文件都统一放在指定的文件夹下
settings中配置文件
MEDIA_ROOT = os.path.join(BASE_DIR,'media')
会直接定义了一个文件夹,然后用户上传注册的文件都会存在里面
查找照片
给图片开设后端接口
url中手动开启后端资源,会将media文件夹下的所有资源暴露给前端
url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT})
搭建个人站点
- 利用有名分组将匹配到的用户站点名传入后端views中的site函数
- 根据穿入的username查询数据库的user对象
- 判断有无,定义404界面
防盗链
- 通过判断当前请求之前的所在地址
- 如果本网站就正常访问,一旦不是则直接禁止
- 请求头里面的
Referer
标识从哪里来的
新建css文件
在media文件夹定义css文件的文件夹css
在css文件夹内根据表的关系定义每个css样式的文件名
link导入css样式
{{blog.site_theme}}
侧边栏展示标签
利用聚合函数进行查询
定义分类栏与标签栏
from django.db.models import Max,Min,Count,Sum,Avg
# 1.查询当前用户每一个分类及分类的文章数(根据个人站点blog得到分类)
category_list = models.Category.objects.filter(blog=blog).annotate(num=Count('article')).values_list('name','num')
# 2.查询当前用户每一个标签及标签下的文章数
tag_list = models.Tag.objects.filter(blog=blog).annotate(num=Count('article')).values_list('name','num')
定义时间栏
临时在表中添加字段
django提供了一个方法
from django.db.models.functions import TruncMonth
-官方提供
from django.db.models.functions import TruncMonth
Sales.objects
.annotate(month=TruncMonth('timestamp')) # Truncate to month and add to select list
.values('month') # Group By month
.annotate(c=Count('id')) # Select the count of the grouping
.values('month', 'c') # (might be redundant, haven't tested) select month and count
按照年月分组
# 3.按照年月分组
date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(num=Count('pk')).values_list('month','num')
前端获取数据
{% for date in date_list %}
<p><a href="#">{{ date.0|date:'Y年m月' }}({{ date.1 }})</a></p>
{% endfor %}
侧边栏筛选功能
侧边栏的对应筛选使用标签\分类\时间格式的拼接使用
博客园的连接
https://www.cnblogs.com/wupeiqi/tag/Python/
https://www.cnblogs.com/wupeiqi/category/850028.html
https://www.cnblogs.com/wupeiqi/archive/2016/07.html
1.侧边栏的设置
利用一个函数接受多天url传来的数据来使用
# 个人站点
url(r'^(?P<username>\w+)/$',views.site,name='username'),
# 个人站点侧边栏筛选功能
# url(r'^(?P<username>\w+)/category/(?P<param>\d+)/',views.site),
# url(r'^(?P<username>\w+)/tag/(?P<param>\d+)/',views.site),
# url(r'^(?P<username>\w+)/archive/(?P<param>\w+)/',views.site),
有多个关键字参数,所以使用**kwargs进行接受,在view中
进行优化
# 个人站点
url(r'^(?P<username>\w+)/$',views.site,name='username'),
url(r'^(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)/',views.site)
侧边栏的展示
# 侧边栏展示
'''
侧边栏筛选功能到底是筛选什么
筛的是当前这个用户下面的所有的文章,再进行筛选
本质其实就是对已经查询出来的article_list再进行筛选操作
'''
if kwargs:
# kwargs是用户根据相应的网址url输入获取到的键值对 {'condition': 'tag', 'param': '1'}
condition = kwargs.get('condition')
# param是网址的后缀数字
param = kwargs.get('param')
# 对用户输入的url数据进行判断
if condition == 'category':
# 按照分类去找列表中筛选
article_list = article_list.filter(category_id=param)
elif condition == 'tag':
# 按照标签去筛选
article_list = article_list.filter(tag_id=param)
else:
# 按照日期去筛选,神奇的双下划线方法
year,month = param.split('-')
article_list = article_list.filter(create_time__year=year,create_time__month=month)
路由分发本质
禁止禁止俄罗斯套娃
url(r'^index/',([
url(r'^index_1/',([
url(r'^index_1_1/',([
],None,None)),
url(r'^index_1_2/',index2),
url(r'^index_1_3/',index1),
],None,None)),
url(r'^index_2/',index2),
],None,None)),
代码
url.py
"""BBS URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/1.11/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: url(r'^$', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: url(r'^$', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.conf.urls import url, include
2. Add a URL to urlpatterns: url(r'^blog/', include('blog.urls'))
"""
from django.conf.urls import url
from django.contrib import admin
from app01 import views
# 图片相关资源
from django.views.static import serve
from BBS import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
# 注册功能
url(r'^register/',views.register,name='register'),
# 登录功能
url(r'^login/',views.login,name='login'),
# 验证码图片
url(r'^get_code/',views.get_code,name='code'),
# 首页搭建
url(r'^home/',views.home,name='home'),
# 退出登录
url(r'^logout/',views.logout,name='logout'),
# 修改密码
url(r'^set_password/',views.set_password,name='set_pwd'),
# 手动开设后端资源,将media文件夹下的所有资源暴露给前端
url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT}),
# 个人站点
url(r'^(?P<username>\w+)/$',views.site,name='username'),
# 个人站点侧边栏筛选功能
# url(r'^(?P<username>\w+)/category/(?P<param>\d+)/',views.site),
# url(r'^(?P<username>\w+)/tag/(?P<param>\d+)/',views.site),
# url(r'^(?P<username>\w+)/archive/(?P<param>\d+)/',views.site),
# 优化
url(r'^(?P<username>\w+)/(?P<condition>category|tag|archive)/(?P<param>.*)/',views.site)
]
views
# 个人站点的搭建
# 侧边栏
from django.db.models import Max,Min,Count,Sum,Avg
# 按照年月分组
from django.db.models.functions import TruncMonth
def site(request,username,**kwargs):
user_obj = models.Userinfo.objects.filter(username=username).first()
# 获取用户的站点
blog = user_obj.blog
# 判断是否有站点,404界面
if not user_obj:
return render(request,'error.html')
# 跳转到个人站点
# 个人站点有当前用户的所有文章,查询所有的文章
article_list = models.Article.objects.filter(blog=blog)
# 侧边栏展示
'''
侧边栏筛选功能到底是筛选什么
筛的是当前这个用户下面的所有的文章,再进行筛选
本质其实就是对已经查询出来的article_list再进行筛选操作
'''
if kwargs:
# kwargs是用户根据相应的网址url输入获取到的键值对 {'condition': 'tag', 'param': '1'}
condition = kwargs.get('condition')
# param是网址的后缀数字
param = kwargs.get('param')
# 对用户输入的url数据进行判断
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('-')
article_list = article_list.filter(create_time__year=year,create_time__month=month)
# 1.查询当前用户每一个分类及分类的文章数(根据个人站点blog得到分类)
category_list = models.Category.objects.filter(blog=blog).annotate(num=Count('article')).values_list('name','num','pk')
# 2.查询当前用户每一个标签及标签下的文章数
tag_list = models.Tag.objects.filter(blog=blog).annotate(num=Count('article')).values_list('name','num','pk')
# 3.按照年月分组
date_list = models.Article.objects.filter(blog=blog).annotate(month=TruncMonth('create_time')).values('month').annotate(num=Count('pk')).values_list('month','num')
return render(request,'site.html',locals())
error.html
<html>
<head>
<meta charset='utf-8' />
<link rel="icon" href="//common.cnblogs.com/favicon.ico" type="image/x-icon" />
<title>404_页面不存在</title>
<style type='text/css'>
body {
margin: 8% auto 0;
max-width: 550px;
min-height: 200px;
padding: 10px;
font-family: 'PingFang SC', 'Microsoft YaHei', 'Helvetica Neue', 'Helvetica', 'Arial', sans-serif;
font-size: 14px;
}
p {
color: #555;
margin: 10px 10px;
}
img {
border: 0px;
}
.d {
color: #404040;
}
</style>
</head>
<body>
<a href='{% url 'home' %}'><img src='/media/avatar/01b19.jpg' alt='cnblogs' /></a>
<p><b>404.</b> 抱歉,您访问的资源不存在。</p>
<p class='d'>请确认您输入的网址是否正确,如果问题持续存在,请憋着,不要与我们联系。</p>
<p><a href='{% url 'home' %}'>返回网站首页</a></p>
</body>
</html>
site.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>个人站点</title>
<script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
{% load static %}
<link rel="stylesheet" href="{% static 'bootstrap-3.3.7-dist/css/bootstrap.min.css' %}">
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
<link rel="stylesheet" href="/media/css/{{ blog.site_theme }}">
</head>
<body>
{#导航条样式#}
<nav class="navbar navbar-inverse">
<div class="container-fluid">
<!-- Brand and toggle get grouped for better mobile display -->
<div class="navbar-header">
<button type="button" class="navbar-toggle collapsed" data-toggle="collapse" data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
<span class="sr-only">Toggle navigation</span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="">{{ user_obj.blog.site_title }}</a>
</div>
<!-- Collect the nav links, forms, and other content for toggling -->
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li><a href="/home/" class="glyphicon glyphicon-home"></a></li>
<li class="active"><a href="#">文章 <span class="sr-only">(current)</span></a></li>
<li><a href="#">随笔</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多 <span class="caret"></span></a>
<ul class="dropdown-menu">
<li><a href="#">Action</a></li>
<li><a href="#">Another action</a></li>
<li><a href="#">Something else here</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">Separated link</a></li>
<li role="separator" class="divider"></li>
<li><a href="#">One more separated link</a></li>
</ul>
</li>
</ul>
<form class="navbar-form navbar-left">
<div class="form-group">
<input type="text" class="form-control" placeholder="Search">
</div>
<button type="submit" class="btn btn-default">Submit</button>
</form>
<ul class="nav navbar-nav navbar-right">
{# 判断用户是否登录 显示登录注册按钮#}
{% if request.user.is_authenticated %}
{# 根据后端,显示登录之后的按钮#}
<li><a href="#">{{ request.user.username }}</a></li>
<li class="dropdown">
<a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-haspopup="true" aria-expanded="false">更多操作 <span class="caret"></span></a>
<ul class="dropdown-menu">
{# 添加模态框的属性data-toggle="modal" data-target="#myModal"#}
<li><a data-toggle="modal" data-target="#myModal">修改密码</a></li>
<li><a href="#">修改头像</a></li>
<li><a href="#">后台管理</a></li>
<li role="separator" class="divider"></li>
<li><a href="{% url 'logout' %}">退出登录</a></li>
</ul>
</li>
{% else %}
{# 没有登录则显示登录注册按钮#}
<li><a href="{% url 'login' %}">登录</a></li>
<li><a href="{% url 'register' %}">注册</a></li>
{% endif %}
</ul>
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
{#整体页面布局#}
<div class="container-fluid">
<div class="row">
{# 左边面板#}
<div class="col-md-3">
<div class="panel panel-primary">
<div class="panel-heading">
<h3 class="panel-title">文章分类</h3>
</div>
{# 添加文章的分类#}
<div class="panel-body">
{% for category in category_list %}
{# 添加分类的连接#}
<p><a href="/{{ username }}/category/{{ category.2 }}/">{{ category.0 }}({{ category.1 }})</a></p>
{% endfor %}
</div>
</div>
<div class="panel panel-danger">
<div class="panel-heading">
<h3 class="panel-title">文章标签</h3>
</div>
<div class="panel-body">
{% for tag in tag_list %}
<p><a href="/{{ username }}/tag/{{ tag.2 }}/">{{ tag.0 }}({{ tag.1 }})</a></p>
{% endfor %}
</div>
</div>
<div class="panel panel-warning">
<div class="panel-heading">
<h3 class="panel-title">日期分类</h3>
</div>
<div class="panel-body">
{% for date in date_list %}
<p><a href="/{{ username }}/archive/{{ date.0|date:'Y-m' }}/">{{ date.0|date:'Y年m月' }}({{ date.1 }})</a></p>
{% endfor %}
</div>
</div>
</div>
{# 文章面板 #}
<div class="col-md-9">
{% for article in article_list %}
{# 媒体对象#}
<div class="media">
{# 标题#}
<h4 class="media-heading"><a href="#">{{ article.title }}</a></h4>
<div class="media-left media-middle">
{# 头像#}
<a href="#">
<img class="media-object" src="/media/{{ article.blog.userinfo.avatar }}/" alt="..." height="60">
</a>
</div>
{# 简介#}
<div class="media-body" id="desc">
{{ article.desc }}
</div>
{# 定义文章的下标#}
<div class="pull-right">
<span>posted </span>
<span>@ </span>
<span>{{ article.create_time|date:'Y-m-d' }} </span>
<span>{{ article.blog.userinfo.username }} </span>
<span><span class="glyphicon glyphicon-comment"></span>评论数({{ article.comment_num }}) </span>
<span><span class="glyphicon glyphicon-thumbs-up"></span>点赞数({{ article.up_num }})</span>
<span><a href="#">编辑</a></span>
</div>
</div>
<hr>
{% endfor %}
</div>
</div>
</div>
{#修改密码的弹出框#}
<!-- Modal -->
<div class="modal fade" id="myModal" tabindex="-1" role="dialog" aria-labelledby="myModalLabel">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<button type="button" class="close" data-dismiss="modal" aria-label="Close"><span aria-hidden="true">×</span></button>
<h4 class="modal-title" id="myModalLabel">修改密码</h4>
</div>
<div class="modal-body">
{# 设置密码的更改#}
<form action="{% url 'set_pwd' %}" method="post">
{% csrf_token %}
<div class="form-group">
<label for="id_username">用户名</label>
<input type="text" id="id_username" name="username" disabled class="form-control" value="{{ request.user.username }}">
</div>
<div class="form-group">
<label for="id_password">初始密码</label>
<input type="password" id="id_password" name="old_password" class="form-control" >
</div>
<div class="form-group">
<label for="id_new_password">新密码</label>
<input type="password" id="id_new_password" name="new_password" class="form-control" >
</div>
<div class="form-group">
<label for="id_confirm_password">确认新密码</label>
<input type="password" id="id_confirm_password" name="confirm_password" class="form-control">
</div>
<div class="modal-footer">
<button type="button" class="btn btn-default" data-dismiss="modal">取消</button>
<button class="btn btn-primary" id="id_s">提交</button>
</div>
</form>
</div>
</div>
</div>
</div>
</body>
</html>