昨日回顾新增内容
在models中创建 1.ForeignKey: on_delete :有很多选项 -models.CASCADE -models.SET_DEFAULT() 2.OneToOneField就是ForeignKey+unique 3.字段类有很多属性: max_length null=True default=‘sss’ unique=True db_index=True verbose_name db_constraint=False 放在ForeignKey,不建立外键关联
1.注册forms编写
from django import forms
from django.forms import widgets
from django.core.exceptions import ValidationError
from .models import UserInfo # 相对导入和绝对导入 此处属于相对导入
class RegisterForm(forms.Form):
# 用户名,密码,确认密码,邮箱
username = forms.CharField(max_length=8, min_length=3, required=True, error_messages={
'max_length': '用户名过长',
'min_length': '用户名过短',
'required': '用户名必填'
}, widget=widgets.TextInput(attrs={'class': 'form-control'}))
password = forms.CharField(max_length=8, min_length=3, required=True, error_messages={
'max_length': '密码过长',
'min_length': '密码过短',
'required': '密码必填'
}, widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
re_password = forms.CharField(max_length=8, min_length=3, required=True, error_messages={
'max_length': '密码过长',
'min_length': '密码过短',
'required': '密码必填'
}, widget=widgets.PasswordInput(attrs={'class': 'form-control'}))
email = forms.EmailField(widget=widgets.EmailInput(attrs={'class': 'form-control'}))
# 局部钩子校验
def clean_username(self):
username = self.cleaned_data.get('username')
user = UserInfo.objects.filter(username=username) # (在django中取值)
if user:
# 已经存在,不合理
return ValidationError('用户名已经存在')
# 不存在,合理 返回校验后的数据
else:
return username
# 全局钩子校验
# 比较两个密码是否一致
def clean(self):
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('两次密码不一致')
2.注册前端页面
# bootstrap 搭建
-settings.py 中 加入static
STATIC_URL = '/static/'
STATICFILES_DIRS=[
os.path.join(BASE_DIR,'static')
]
-把bootstrap的静态资源copy到static文件夹下
# 新建模板文件 register.html
<!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>
3 头像动态显示
<!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">
{% 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 () {
var reader=new FileReader()
var file =$("#id_file")[0].files[0]
reader.readAsDataURL(file)
reader.onload=function (){
$('#id_img').attr('src', reader.result)
}
})
</script>
4 注册功能后端
def register(request):
if request.method == 'GET':
register_form = RegisterForm()
return render(request, 'register.html', context={'form': register_form})
else:
res = {'code': 100, 'msg': '注册成功'}
register_form = RegisterForm(data=request.POST)
if register_form.is_valid():
register_data = register_form.cleaned_data
register_data.pop('re_password')
my_file = request.FILES.get('my_file')
if my_file:
register_data['avatar'] = my_file
UserInfo.objects.create_user(**register_data)
return JsonResponse(res)
else:
res['code'] = 101
res['msg'] = '注册失败'
res['errors'] = register_form.errors
return JsonResponse(res)
5 注册功能前端
<!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 () {
var reader = new FileReader()
var file = $("#id_file")[0].files[0]
reader.readAsDataURL(file)
reader.onload = function () {
$('#id_img').attr('src', reader.result)
}
})
$("#id_submit").click(function () {
var formdata = new FormData()
var data = $("#id_form").serializeArray()
console.log(data)
$.each(data, function (i, v) {
formdata.append(v.name, v.value)
})
formdata.append('my_file', $('#id_file')[0].files[0])
$.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>
6 头像上传路径问题
#咱们写项目后台静态资源中得图片,一般放在static文件夹下 #用户上传的文件,图片等,一般放在media文件夹下 -我们想做的是,avatar文件夹要在media文件夹下
#django中只需要在配置文件中加一句话 #以后再上传的文件路径是从media文件夹下开始 MEDIA_ROOT = os.path.join(BASE_DIR, ‘media’)
7 注册错误信息渲染
$("#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)
}
}
})
})
8 用户存在校验功能
8.1 后端校验接口
/check_username/?username=lqz
def check_username(request):
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)
8.2 前端
// 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)
}
}
})
})
|