04 用户注册
基于forms组件创建表单
创建forms
from django import forms from django.forms import widgets class UserInfo(forms.Form): user=forms.CharField(max_length=32,label="用户名",widget=widgets.TextInput(attrs={"class":'form-control'})) pwd=forms.CharField(max_length=32,label="密码",widget=widgets.PasswordInput(attrs={"class":"form-control"})) re_pwd=forms.CharField(max_length=32,label="确认密码",widget=widgets.PasswordInput(attrs={"class":"form-control"})) email=forms.EmailField(max_length=32,label="邮箱地址",widget=widgets.EmailInput(attrs={"class":'form-control'}))
html中渲染forms组件
<form> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}:</label>{{ field }} </div> {% endfor %} <input type="button" class="button form-control btn-success" value="提交"> </form>
添加用户头像
添加用户图像图标
添加一个img标签,连接到static下的一个default.png文件
技巧:
- 利用label的for属性,让点击图片等同于点击input标签
- 将input[type='file']的标签隐藏掉,设置display属性为none
<div class="container"> <div class="row"> <div class="col-md-4 col-lg-offset-4"> <form> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.id_for_label }}">{{ field.label }}:</label>{{ field }} </div> {% endfor %} <div class="form-group"> <label for="avatar">头像 <img class="avatar_img" src="/static/app/img/default.png" style="width: 60px;height: 60px;display: inline"> </label> <input type="file" id="avatar" style="display: none;"> </div> <input type="button" class="button form-control btn-success" value="提交"> </form> </div> </div> </div>

用户头像预览功能
- 获取用户选中的文件对象,通过input标签的change事件来触发
- 获取文件对象的本地路径,一定要等图片加载完成之后再来获取文件路径
- 修改img的src属性值
<script> $('#avatar').change(function () { //获取用户选中的文件对象 var file_obj=$(this)[0].files[0]; //获取当前文件对象路径 var reader=new FileReader();//实例化一个reader reader.readAsDataURL(file_obj);//读取文件对象路径,读取完成后放在reader自己内部 //待读取完后,获取url和修改imgsrc属性 reader.onload=function () { var file_url=reader.result;//获取文件路径url //修改img标签的src属性 $('#avatar_img').attr('src',file_url); }; }) </script>

用ajax提交formdata数据
ajax数据提交
- 上传的data为formdata,需要new一个
- contentType为false
- processData为false
方式一创建formdata的ajax代码
<script>
//提交formdata数据
$('input[type="button"]').click(function () {
var formdata=new FormData();
formdata.append("user",$("#id_user").val());
formdata.append("pwd",$("#id_pwd").val());
formdata.append("re_pwd",$("#id_re_user").val());
formdata.append("email",$("#id_email").val());
formdata.append("avatar",$("#avatar")[0].files[0]);
formdata.append("csrfmiddlewaretoken",$("input[name='csrfmiddlewaretoken']").val());
$.ajax({
url:'',
data:formdata,
type:'post',
contentType:false,
processData:false,
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
})
</script>
方式二创建formdata
<script>
//提交formdata数据
$('input[type="button"]').click(function () {
var formdata=new FormData();formdata.append("csrfmiddlewaretoken",$("input[name='csrfmiddlewaretoken']").val());#}
var formarray= $("#form").serializeArray();
$.each(formarray,function (index, data) {
formdata.append(data.name,data.value);
});
formdata.append("avatar",$("#avatar")[0].files[0]);
$.ajax({
url:'',
data:formdata,
type:'post',
contentType:false,
processData:false,
success:function (data) {
console.log(data)
},
error:function (err) {
console.log(err)
}
})
})
</script>
views代码,可通过is_ajax()验证,也可以通过request.POST验证
def register(request): # if request.method=='POST': if request.is_ajax(): response={"user":None,"msg":None} form=UserInfoForm(request.POST) if form.is_valid(): response['user']=form.cleaned_data.get('user'); else: print(form.cleaned_data) print(form.errors) response['msg']=form.errors return JsonResponse(response)
加载error提示
- 通过jquery的each方法循环errs,每个error的index对应的和input的id有规律,其实也可以用name直接获取。查找到input标签后,通过next方法查找下一个标签
- 在将error写入span之前,需要将所有的error信息清除掉,否则第二次提交的是第一次的error信息任然
JavaScript代码
<script>
//提交formdata数据
$('input[type="button"]').click(function () {
var formdata=new FormData();
var formarray= $("#form").serializeArray();
$.each(formarray,function (index, data) {
formdata.append(data.name,data.value);
});
formdata.append("avatar",$("#avatar")[0].files[0]);
$.ajax({
url:'',
data:formdata,
type:'post',
contentType:false,
processData:false,
success:function (data) {
if(data.msg){
//数据校验失败,导致注册失败
//动态加载错误信息
$(".error").html("");//先清空一次,避免上次错误信息任然存在
$(".form-group").removeClass('has-error');
$.each(data.msg,function (index,error_list) {
$("#id_"+index).next().html(error_list[0]);
$("#id_"+index).parent().addClass('has-error');//错误字段边框变红
})
}else{
//注册成功
}
},
error:function (err) {
console.log(err)
}
})
})
</script>

错误信息修改成中文提示
在form字段中,添加error_message参数
class UserInfo(forms.Form): user=forms.CharField(max_length=32,label="用户名", widget=widgets.TextInput(attrs={"class":'form-control'}), error_messages={"required":"用户名不能为空"}) pwd=forms.CharField(max_length=32,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"密码不能为空"}) re_pwd=forms.CharField(max_length=32,label="确认密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"确认密码不能为空"}) email=forms.EmailField(max_length=32,label="邮箱地址", widget=widgets.EmailInput(attrs={"class":'form-control'}), error_messages={"required":"邮箱不能为空"})

钩子校验数据
局部钩子检查用户名是否已经注册
class RegisterUser(forms.Form): user=forms.CharField(max_length=32,label="用户名", widget=widgets.TextInput(attrs={"class":'form-control'}), error_messages={"required":"用户名不能为空"}) pwd=forms.CharField(max_length=32,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"密码不能为空"}) re_pwd=forms.CharField(max_length=32,label="确认密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"确认密码不能为空"}) email=forms.EmailField(max_length=32,label="邮箱地址", widget=widgets.EmailInput(attrs={"class":'form-control'}), error_messages={"required":"邮箱不能为空"}) #局部钩子校验用户 def clean_user(self): val=self.cleaned_data.get('user') user=UserInfo.objects.filter(username=val).first() if not user: #返回原来的val return val else: raise ValidationError("该用户已注册")
全局钩子检查两次密码是否一致
class RegisterUser(forms.Form): user=forms.CharField(max_length=32,label="用户名", widget=widgets.TextInput(attrs={"class":'form-control'}), error_messages={"required":"用户名不能为空"}) pwd=forms.CharField(max_length=32,label="密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"密码不能为空"}) re_pwd=forms.CharField(max_length=32,label="确认密码", widget=widgets.PasswordInput(attrs={"class":"form-control"}), error_messages={"required":"确认密码不能为空"}) email=forms.EmailField(max_length=32,label="邮箱地址", widget=widgets.EmailInput(attrs={"class":'form-control'}), error_messages={"required":"邮箱不能为空"}) #全局钩子验证两次密码 def clean(self): pwd=self.cleaned_data.get('pwd') re_pwd=self.cleaned_data.get('re_pwd') if pwd and re_pwd: if pwd == re_pwd: return self.cleaned_data else: raise ValidationError('两次密码不一致') else: return self.cleaned_data
注意:全局钩子的错误放在__all__中的,所以each循环的时候判断是否是__all__即可判断是否为全局错误信息

前端JavaScript展示全局错误信息
<script>
//提交formdata数据
$('input[type="button"]').click(function () {
var formdata=new FormData();
var formarray= $("#form").serializeArray();
$.each(formarray,function (index, data) {
formdata.append(data.name,data.value);
});
formdata.append("avatar",$("#avatar")[0].files[0]);
$.ajax({
url:'',
data:formdata,
type:'post',
contentType:false,
processData:false,
success:function (data) {
if(data.msg){
//数据校验失败,导致注册失败
//动态加载错误信息
$(".error").html("");//先清空一次,避免上次错误信息任然存在
$(".form-group").removeClass('has-error');
$.each(data.msg,function (index,error_list) {
if(index == '__all__'){//
$("#id_re_pwd").next().text(error_list[0])
}
$("#id_"+index).next().html(error_list[0]);
$("#id_"+index).parent().addClass('has-error');//错误字段边框变红
})
}else{
//注册成功
}
},
error:function (err) {
console.log(err)
}
})
})
</script>

所有数据校验通过
添加用户记录
def register(request): # if request.method=='POST': if request.is_ajax(): response={"user":None,"msg":None} form=RegisterUser(request.POST) if form.is_valid(): response['user']=form.cleaned_data.get('user') user=form.cleaned_data.get('user') pwd=form.cleaned_data.get('pwd') email=form.cleaned_data.get('email') avatar_obj=request.FILES.get('avatar') if avatar_obj: UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar=avatar_obj) else: #用户没有上传头像则不能传入avatar参数,不传和传空是不一样的 UserInfo.objects.create_user(username=user, password=pwd, email=email) else: response['msg']=form.errors return JsonResponse(response) form=RegisterUser() return render(request,'register.html',{"form":form})
用户校验成功,前端跳转到登录界面
if (data.user){ //用户校验成功,跳转到登录界面 location.href='/login/'; }
django静态文件
django有两种静态文件:
/static/ 前端需求资源
/media/ 所有用户上传的文件都在该文件夹中
django配置media文件件配置,在setting文件中操作

一旦配置过media,那么FileField中上传的文件将放置在media中


浙公网安备 33010602011771号