BBS项目开发2
作者:互联网
注册forms编写
专门写一个类来存form
用户名、密码、确认密码、邮箱
username = forms.CharField(max_length=8, min_length=3,required=True,error_massages={'max_length':'超出范围','min_length':'太短了','required':'这个必填'}, widget=widgets.TextInput(attrs={'class': 'form-control'}))
"""
max_length:限制最长
min_length:限制最短
required:设置这个是必须要填的
error_massages:提示错误信息
widget:渲染页面,添加一个额外属性,对某一个filed指定widget,传递一个attrs,是一个字典
"""
钩子函数校验
局部钩子校验:(clean_字段名)
def clean_username(self):
# 先将名字取出来
username=self.cleaned_data.get('username')
# 去数据库中比对该用户
user=UserInfo.objects.filter(username=username).first()
if user:
# 已经存在,不合理
raise ValidationError('该用户名已经存在')
else:
return username
全局钩子校验:(clean)校验多个用户
def clean(self):
# 比较两个密码是否一致 :cleaned_data存的是校验过后的数据,是个字典
password = self.cleaned_data.get('password')
re_password = self.cleaned_data.get('re_password')
if password == re_password:
# 合理,返回校验过后的数据
return self.cleaned_data
else:
# 不合理,抛出校验失败的异常
raise ValidationError('两次密码不一致!!')
注册页面搭建
在settings.py中配置静态资源的配置
STATIC_URL= '/static/'
STATICFILES_DIRS=[os.path.join(BASE_DIR, 'static')]
-把bootstrap的静态资源copy到static文件夹下
"""
前端页面使用的是bookstrap搭建的
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
</div>
</div>
</div>
可以使用for循环来将我们在form里面写的所有字段写出来,那么需要我们将数据传过来,进入views.py中,实例化一个对象,然后render的第三个参数context用来传输上下文,将数据传给前端
# 将文件导入
from blog.blog_forms import RegisterForm
if request.method == 'GET':
# register_form是我们写的那个类,
register_form = RegisterForm()
return render(request, 'register.html', context={'form': register_form})
"""
{% for item in form %}
<div class="form-group">
<label for="{{ item.id_for_label }}">{{ item.label }}</label>
{{ item }}
<span class="pull-right text-danger"></span>
</div>
{% endfor %}
头像要单独写出来不能写的fo循环里
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1 class="text-center">注册功能</h1>
<form id="id_form">
{% for item in form %}
<div class="form-group">
<label for="{{ item.id_for_label }}">{{ item.label }}</label>
{{ item }}
<span class="pull-right text-danger"></span>
</div>
{% endfor %}
<div class="form-group">
<label for="id_file">头像
<img src="/static/img/default.png" alt="" height="80px" width="80px" style="margin-left: 10px">
</label>
<input type="file" id="id_file" accept="image/*" style="display: none">
</div>
<div class="form-group text-center">
{# 如果input类型是submit或者button标签,放在form表单中,如果点提交,触发form的提交,如果我们写了ajax提交,会触发两次提交#}
<input type="button" value="注册" class="btn btn-danger" id="id_submit">
<span class="text-danger"></span>
</div>
</form>
</div>
</div>
</div>
</body>
</html>
头像动态显示
1.给头像img标签设置一个id
2.给这个id设置一个change事件,如果图片发生了变化,那么就触发这个事件
3.借助于一个文件阅读器,它是js提供的一个类
var reader=new FileReader()
4.拿到文件对象,赋值给一个变量
<label for="id_file">头像<img src="/static/img/default.png" alt="" height="80px" width="80px" style="margin-left: 10px" id="id_img"></label>
<input type="file" id="id_file" accept="image/*" style="display: none">
var file = $("#id_file")[0].files[0]
5.把文件读到文件阅读器中
reader.readAsDataURL(file)
6.等读完后,把文件阅读器的内容写到img标签上
reader.onload=function (){
$('#id_img').attr('src', reader.result)
}
后端注册功能
def register(request):
# get请求部分
if request.method == 'GET':
register_form = RegisterForm()
return render(request, 'register.html', context={'form': register_form})
# post请求部分
else:
res = {'code': 100, 'msg': '注册成功'}
# 取出用固话名密码,使用form校验数据,如果校验通过,存到数据库中。如果校验不通过,返回错误信息
register_form = RegisterForm(data=request.POST) # data就是校验的数据
if register_form.is_valid():
# 数据字段自己的规则,局部钩子,全局钩子都校验过后,通过了然后要存到数据库中
# 1.re_password字段不能存入数据库中,要删除掉
# cleaned_data是校验过后的数据,赋值给变量
register_data = register_form.cleaned_data
# 从cleaned_data中将re_password剔除
register_data.pop('re_password')
# 2.头像:如果携带了要存褚在request.FILES中
my_file = request.FILES.get('my_file') # my_file是一个对象
if my_file:
# 直接把文件对象赋值给avatar后,保存成功,会把文件存放到FileField 的upload_to指定的路径下,然后该字段存放地址
# 本质 打开了空文件,把前端传入的头像存到空文件中,然后把地址存到avatar这个地段上
register_data['avatar'] = my_file
# 3.存到数据库
UserInfo.objects.create_user(**register_data)
return JsonResponse(res)
else:
res['code'] = 101
res['msg'] = '注册失败'
res['errors'] = register_form.errors
return JsonResponse(res)
注册功能前端
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css">
<script src="/static/jquery-3.3.1/jquery-3.3.1.min.js"></script>
</head>
<body>
<div class="container-fluid">
<div class="row">
<div class="col-md-6 col-md-offset-3">
<h1 class="text-center">注册功能</h1>
<form id="id_form" >
{% csrf_token %}
{% for item in form %}
<div class="form-group">
<label for="{{ item.id_for_label }}">{{ item.label }}</label>
{{ item }}
<span class="pull-right text-danger"></span>
</div>
{% endfor %}
<div class="form-group">
<label for="id_file">头像
<img src="/static/img/default.png" alt="" height="80px" width="80px" style="margin-left: 10px"
id="id_img">
</label>
<input type="file" id="id_file" accept="image/*" style="display: none">
</div>
<div class="form-group text-center">
{# 如果input类型是submit或者button标签,放在form表单中,如果点提交,触发form的提交,如果我们写了ajax提交,会触发两次提交#}
<input type="button" value="注册" class="btn btn-danger" id="id_submit">
<span class="text-danger"></span>
</div>
</form>
</div>
</div>
</div>
</body>
<script>
$("#id_file").change(function () {
// 把当前图片,放到img标签中
// 把图片地址放到img标签上,标签就显示了图片
//$("#id_img")[0].src='https://tva1.sinaimg.cn/large/00831rSTly1gd1u0jw182j30u00u043b.jpg'
// 1 id_file这个标签的图片读出来,借助于文件阅读器,js提供的一个类
var reader = new FileReader()
// 2 拿到文件对象,赋值给一个变量
var file = $("#id_file")[0].files[0]
// 3 把文件读到文件阅读器中
reader.readAsDataURL(file)
// 4 等读完后,把文件阅读器的内容写到img标签上
//$("#id_img")[0].src=reader.result
reader.onload = function () {
//$("#id_img")[0].src=reader.result
$('#id_img').attr('src', reader.result)
}
})
// 当点击注册按钮,发送ajax请求到后端的注册功能
$("#id_submit").click(function () {
// 上传文件,借助于formdata对象
var formdata = new FormData()
// 方式一
/*
formdata.append('username',$('#id_username').val())
formdata.append('password',$('#id_username').val())
formdata.append('re_password',$('#id_username').val())
formdata.append('my_file',$('#id_file')[0].files[0])
// csrftoken也要加上
*/
// 方式二:借助于form表单批量处理
var data = $("#id_form").serializeArray()
console.log(data)
// 使用for循环,把data中得数据,转存到formdata中 jquery的each循环
$.each(data, function (i, v) {
//console.log("索引是:",i)
//console.log("值是:",v)
//console.log("------")
formdata.append(v.name, v.value)
})
// 文件单独再放进去
formdata.append('my_file', $('#id_file')[0].files[0])
// 使用ajax向后端发送请求
// 1 三种编码格式:urlencoded,form-data,json
// {name:lqz,age:19}--->name=lqz&age=19
$.ajax({
url: '/register/',
type: 'post',
processData: false,
contentType: false,
data: formdata,
success: function (data) {
console.log(data)
if(data.code==100){
// 表示注册成功,跳转到登录页面
location.href='/login/'
}else {
// 在前端显示错误信息
}
}
})
})
</script>
</html>
头像上传路径问题
# 咱们写项目后台静态资源中得图片,一般放在static文件夹下
# 用户上传的文件,图片等,一般放在media文件夹下
-我们想做的是,avatar文件夹要在media文件夹下
# django中只需要在配置文件中加一句话
# 以后再上传的文件路径是从media文件夹下开始
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
注册错误信息渲染
$("#id_submit").click(function () {
// 上传文件,借助于formdata对象
var formdata = new FormData()
// 方式一
/*
formdata.append('username',$('#id_username').val())
formdata.append('password',$('#id_username').val())
formdata.append('re_password',$('#id_username').val())
formdata.append('my_file',$('#id_file')[0].files[0])
// csrftoken也要加上
*/
// 方式二:借助于form表单批量处理
var data = $("#id_form").serializeArray()
console.log(data)
// 使用for循环,把data中得数据,转存到formdata中 jquery的each循环
$.each(data, function (i, v) {
//console.log("索引是:",i)
//console.log("值是:",v)
//console.log("------")
formdata.append(v.name, v.value)
})
// 文件单独再放进去
formdata.append('my_file', $('#id_file')[0].files[0])
// 使用ajax向后端发送请求
// 1 三种编码格式:urlencoded,form-data,json
// {name:lqz,age:19}--->name=lqz&age=19
$.ajax({
url: '/register/',
type: 'post',
processData: false,
contentType: false,
data: formdata,
success: function (data) {
console.log(data)
if(data.code==100){
// 表示注册成功,跳转到登录页面
location.href='/login/'
}else {
// 在前端显示错误信息
console.log(data)
// 两次密码不一致的错误渲染
/*
if(data.errors['__all__']){
$(".error").html(data.errors['__all__'][0])
}
*/
// 其他标签的错误渲染
$.each(data.errors,function (k,v){
if (k=='__all__'){ //两次密码不一致的错误渲染
$(".error").html(v[0])
}else {
// 链式调用,在对应的input后的span中插入错误文字,把父div加入has-error类,整个框变红
$("#id_"+k).next().html(v[0]).parent().addClass('has-error')
}
})
// 起一个定时任务
setTimeout(function (){
// 把所有span的文字去掉,把父div中得has-error类去掉
$('.text-danger').html("").parent().removeClass('has-error')
},3000)
}
}
})
})
用户校验功能呢
后端校验接口
# 前端通过get把用户名传入,我们根据用户名查询数据库,如果用户名存在,返回存在,如果不存在,返回不存在
/check_username/?username=lqz
def check_username(request):
# /check_username/?username=lqz
res = {'code': 100, 'msg': '用户存在'}
username = request.GET.get('username')
user = UserInfo.objects.filter(username=username).first()
if user:
# 用户存在
return JsonResponse(res)
else:
# 用户不存在
res['code'] = 101
res['msg'] = '用户不存在'
return JsonResponse(res)
前端
// username输入框,失去焦点,触发ajax执行
$('#id_username').blur(function () {
$.ajax({
url: '/check_username/?username=' + $(this).val(),
type: 'get',
success: function (data) {
if (data.code == 100) {
// 在span中插入错误信息
{#alert(data.msg)#}
$('#id_username').next().html(data.msg)
}
}
})
})
标签:username,form,项目,BBS,formdata,开发,file,data,id 来源: https://www.cnblogs.com/zxr1002/p/16698300.html