BBS项目day2
一 服务器保存文件父路径
例如昨天的头像上传,使保存到的文件夹都处在父路径之下
models.py中不需要动
avatar = models.FileField(upload_to='avatar/', default='avatar/default.png')
settings.py中配置
MEDIA_ROOT=os.path.join(BASE_DIR,'media')
# 由于FileField会自动保存文件,所以默认以MEDIA_ROOT开始往下找,如果没有配,默认以根路径开始
# 以后上传的文件,都是从media路径往下找
二 注册功能错误渲染
注册时提示出错,如两次密码不一致,用户已存在,格式不正确,这些都是用户离开输入框就触发的功能,而不用刷新网页,所以必然是在ajax里实现的功能
接着昨天注册功能里的ajax部分进行补全
$.ajax({
url: '/register/',
method: 'post',
processData: false,
contentType: false,
data: formdata,
success: function (data) {
// 没有错误
if (data.code == 100) {
console.log(data.msg)
//js控制的跳转
location.href = data.url
} else {
//有错误,需要渲染页面
$.each(data.error, function (k, v) {
// 当错误为全局钩子的错误时(也就是两次密码不一致),将错误信息渲染到注册按钮旁的error类(自己去建!别老想着copy)
if (k == '__all__') {
$(".error").html(v)
}
// 将错误信息渲染到id_name的下一个标签(错误信息的span标签),同时给其父标签添加类has-error(bootstrap的染红输入框)
$("#id_" + k).next().html(v[0]).parent().addClass('has-error')
})
//过三(3000毫秒)秒钟,错误信息清除,在匿名函数中执行
setTimeout(function () {
// 将所有,含有红色文本类的标签清空文本,同时给其父标签删掉染红输入框
$('.text-danger').html("").parent().removeClass('has-error')
}, 3000)
}
}
})
})
三 用户名变化校验
视图函数
def check_username(request):
print('xxx')
res = {'code': 101, 'msg': '该用户已经存在了小兄弟'}
username = request.GET.get('username')
user = models.UserInfo.objects.filter(username=username).count()
if not user:
res['code'] = 100
res['msg'] = '不存在'
return JsonResponse(res)
js代码
// blur:当光标离开控件上时触发
$('#id_username').blur(function () {
//this 原生空间,使用它$(),它才变成jq,使用jq的方法
//alert($(this).val())
//alert($('#id_username').val())
$.ajax({
url: '/check_username/?username=' + $(this).val(),
method: 'get',
success: (data) => {
if (data.code !== 100) {
/*这里的success如果没用箭头语法,则会因为作用域的原因,this得到的是None*/
$(this).next().html(data.msg).parent().addClass('has-error')
}
}
/*
success: function (data) {
if(data.code !==100){
这里如果用this就会错误!!作用域问题,success用上es6的箭头语法则可以避免
$('#id_username').next().html(data.msg).parent().addClass('has-error')
}
}
*/
})
})
四 登陆页面搭建
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
<title>登录</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1 class="text-center">登录功能</h1>
<div class="col-md-6 col-md-offset-3">
<form id="form">
{% csrf_token %}
<div class="form-group">
<label for="">用户名</label>
<input type="text" name="username" class="form-control">
</div>
<div class="form-group">
<label for="">密码</label>
<input type="password" name="password" class="form-control">
</div>
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="valid_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/static/img/default.png" height="30" width="450">
</div>
</div>
</div>
<div class="text-center">
<input type="button" value="登录" id="id_submit" class="btn btn-danger"><span
class="error text-danger" style="margin-left: 10px"></span>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
五 图片验证码
自定义图片验证码
随机生成rgb数字的函数
# 数字越大颜色越浅
def get_rgb():
return (random.randint(0, 255), random.randint(0, 255), random.randint(0, 255))
生成函数
需要先导入pillow模块:from PIL import Image, ImageDraw, ImageFont
还有将二进制存入内存的模块:from io import BytesIO
def get_valid(request):
# 方式一,直接返回一张图片
# with open('./lhf.jpg','rb') as f:
# data=f.read()
# return HttpResponse(data)
# 方式二:自己生成一张图片,返回
# pillow模块:图片处理模块,pip3 install pillow
# 需要先导入pillow模块:from PIL import Image, ImageDraw, ImageFont
# 生成一张图片(Image模块下的new函数,返回一个Image对象)
# img = Image.new('RGB', (450, 30), (123, 123, 255))
# # 图片保存(写到硬盘)
# with open('a.png', 'wb') as f:
# img.save(f)
# # 打开图片
# with open('./a.png', 'rb') as f:
# data = f.read()
# return HttpResponse(data)
## 方式三:把生成的图片写到内存中
# 需要先引入:from io import BytesIO
# img = Image.new('RGB', (450, 30), (123, 123, 255))
# # 图片保存(写到内存中)
# f=BytesIO()
# img.save(f,'png') # 指定图片格式
# # 打开图片
# data=f.getvalue() # 把内容全取出来
# return HttpResponse(data)
## 方法四:在图片上写文字
# img = Image.new('RGB', (450, 30), (123, 123, 255))
#
# # 把图片放到画板上
# img_draw=ImageDraw.Draw(img)
# # 在x轴0,y轴0的位置写文字
# img_draw.text((0,0),'python')
#
# f=BytesIO()
# img.save(f,'png')
# data=f.getvalue()
# return HttpResponse(data)
## 方式五:图片上写文字,字体是指定的字体,字的颜色随机
# img = Image.new('RGB', (450, 30), (123, 123, 255))
#
# img_draw = ImageDraw.Draw(img)
# img_font = ImageFont.truetype('./static/font/xgdl.ttf', 23) # 字体文件,字号大小23
# img_draw.text((0, 0), 'python', (255, 0, 255), img_font) # 位置,内容,字体颜色,字体
#
# f = BytesIO()
# img.save(f, 'png')
# data = f.getvalue()
# return HttpResponse(data)
## 方式6 最终方案
# img = Image.new('RGB', (450, 30), get_rgb()) # get_rgb():使用随机生成rgb数字的函数
img = Image.new('RGB', (450, 30), (255,255,255))
img_draw = ImageDraw.Draw(img)
img_font = ImageFont.truetype('./static/font/ss.TTF', 25)
# 随机生成5个大写字母,小写字母,数字
valid_code=''
for i in range(5):
low_char = chr(random.randint(97, 122))
num_char = random.randint(0, 9)
upper_char = chr(random.randint(65, 90))
res = random.choice([low_char, num_char, upper_char])
valid_code+=str(res)
img_draw.text((i*63+50, 0), str(res), get_rgb(), img_font)
print(valid_code) # 打印验证码
# 把验证码存到session中,使每个用户都有其独特的验证码
request.session['valid_code']=valid_code
# 画线和点圈,这个请直接copy
width = 450
height = 30
for i in range(10): # 画十根线
x1 = random.randint(0, width)
x2 = random.randint(0, width)
y1 = random.randint(0, height)
y2 = random.randint(0, height)
# 在图片上画线
img_draw.line((x1, y1, x2, y2), fill=get_rgb())
for i in range(50): # 画50个点跟弧形
# 画点
img_draw.point([random.randint(0, width), random.randint(0, height)], fill=get_rgb())
x = random.randint(0, width)
y = random.randint(0, height)
# 画弧形
img_draw.arc((x, y, x + 4, y + 4), 0, 90, fill=get_rgb())
f = BytesIO()
img.save(f, 'png')
data = f.getvalue()
return HttpResponse(data) # 因为要随时刷新换图片,所以是传给ajax的数据,用HttpResponse
借助第三方模块实现验证码
六 点击图片验证码更新
$("#id_valid_code").click(function () {
var url = $("#id_valid_code")[0].src
$("#id_valid_code")[0].src = url + '?' // src变换时就会发送一次请求,这里的方法是添加无意义的问号
})
七 登陆功能
后台
def login(request):
if request.method == 'GET':
return render(request, 'login.html')
else:
res = {'code': 100, 'msg': None}
username = request.POST.get('username')
password = request.POST.get('password')
valid_code = request.POST.get('valid_code')
# 校验验证码是否正确,忽略大小写
if request.session.get('valid_code').upper() == valid_code.upper():
# 不使用这个
# models.UserInfo.objects.filter(username=username,password=password)
user = auth.authenticate(username=username, password=password)
if user:
# 调用一些login
auth.login(request, user)
res['msg'] = '登录成功'
res['url'] = '/index/'
else:
res['code'] = 101
res['msg'] = '用户名或密码错误'
else:
res['code'] = 102
res['msg'] = '验证码错误'
return JsonResponse(res)
前台
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
<title>登录</title>
</head>
<body>
<div class="container-fluid">
<div class="row">
<h1 class="text-center">登录功能</h1>
<div class="col-md-6 col-md-offset-3">
<form id="form">
{% csrf_token %}
<div class="form-group">
<label for="">用户名</label>
<input type="text" name="username" class="form-control">
</div>
<div class="form-group">
<label for="">密码</label>
<input type="password" name="password" class="form-control">
</div>
<div class="form-group">
<label for="">验证码</label>
<div class="row">
<div class="col-md-6">
<input type="text" name="valid_code" class="form-control">
</div>
<div class="col-md-6">
<img src="/get_valid/" height="30" width="450" id="id_valid_code">
</div>
</div>
</div>
<div class="text-center">
<input type="button" value="登录" id="id_submit" class="btn btn-danger"><span
class="error text-danger" style="margin-left: 10px"></span>
</div>
</form>
</div>
</div>
</div>
</body>
<script>
$("#id_valid_code").click(function () {
var url = $("#id_valid_code")[0].src
$("#id_valid_code")[0].src = url + '?'
})
$("#id_submit").click(function () {
//不建议在js中写模板语法
$.ajax({
url: '/login/',
method: 'post',
data: {
'username': $('[name="username"]').val(),
'password': $('[name="password"]').val(),
'valid_code': $('[name="valid_code"]').val(),
'csrfmiddlewaretoken': $('[name="csrfmiddlewaretoken"]').val()
},
success:function (data) {
if(data.code==100){
location.href=data.url
}else {
$('.error').html(data.msg)
}
}
})
})
</script>
</html>
八 博客首页导航条
后台
def index(request):
return render(request, 'index.html')
def logout(request):
auth.logout(request)
return redirect('/')
前台
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
<script src="/static/bootstrap/js/bootstrap.min.js"></script>
<title>博客园首页</title>
</head>
<body>
<div class="head">
<nav class="navbar navbar-default">
<div class="container-fluid">
<div class="navbar-header">
<a class="navbar-brand" href="#">博客园</a>
</div>
<div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
<ul class="nav navbar-nav">
<li class="active"><a href="/index/">首页 <span class="sr-only">(current)</span></a></li>
<li><a href="#">新闻</a></li>
</ul>
{% if request.user.is_authenticated %}
<ul class="nav navbar-nav navbar-right">
<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">
<li><a href="#">修改密码</a></li>
<li><a href="#">修改头像</a></li>
<li role="separator" class="divider"></li>
<li><a href="/logout/">退出登录</a></li>
</ul>
</li>
</ul>
{% else %}
<ul class="nav navbar-nav navbar-right">
<li><a href="/login/">登录</a></li>
<li><a href="/register/">注册</a></li>
</ul>
{% endif %}
</div><!-- /.navbar-collapse -->
</div><!-- /.container-fluid -->
</nav>
</div>
<div class="container-fluid">
<div class="body">
<div class="row">
<div class="left_content col-md-2"></div>
<div class="middle_content col-md-7"></div>
<div class="right_content col-md-3"></div>
</div>
</div>
</div>
</body>
</html>
补充异步知识
-
程序:躺在硬盘上就是一堆文件,加载到内存,就是一堆指令,被cpu调度执行
-
进程,线程,协程
-
进程是资源分配的最小单位 跨进程通信 IPC ,通过共享变量实现不了,借助Queue,借助文件,借助数据库,借助redis,借助消息队列(专业干这个事)
-
线程是cpu调度的最小单位(程序执行的最小单位),线程通信:共享变量(并发安全问题,锁,分布式锁,悲观锁,乐观锁)
-
协程:当线程下实现并发(保存状态+切换)
-
一旦使用了异步,后续全用异步
-
await 和 async 关键字
async:声明协程函数
await:io操作前面加