django框架之BBS项目之注册 未完待续
内容回顾
1. BBS项目登录
1. 登录用form组件和auth模块
1. form组件做校验很方便
2. auth模块
- authenticate(username=xxx, password=xxx)
- login(request, user_obj)
2. 验证码
1. PIL模块的使用
2. from io import BytesIO --> 查一下
io_obj = BytesIO()
io_obj.getvalue() --> 从io对象取值的方法
3. 多对多的三种方式
1. ManyToManyField自动生成第三张表的方式
1. 优势
有连表操作的快捷方法
1. all()
2. add(obj)
3. remove()
4. set([])
5. clear()
2. 劣势
第三章关系表的字段是固定的,没有办法扩展
2. 自己创建第三张表
在第三章表中分别通过外键关联两张表
1. 优势
可以添加自定义的其他字段
2. 劣势
跨表查询比较繁琐(需要跨三张表查询)
3. 自己创建第三张表,在ManyToManyField字段中通过through和through_fields两个属性进行配置
1. 优势:
1. 在关系表中可以添加自定义的其他字段
2. 可以使用快捷查询方法:.all()
4. JS的正则
1. 生成RegExp对象的方式
2. 简写方式
今天是写注册的功能。
首先是在form组件中写注册的表单类:
forms.py代码:
from django.core.validators import RegexValidator from django.core.exceptions import ValidationError #注册 Form类 class RegisterForm(forms.Form): username = forms.CharField( label='用户名', min_length=4, error_messages={ 'required':'用户名不得为空', 'min_length':'用户名不得少于4位', }, widget=forms.widgets.TextInput(attrs={'class':'form-control'}) ) password = forms.CharField( label='密码', min_length=6, error_messages={ 'required':'密码不能为空', 'min_length':'密码不得少于6位', }, widget=forms.widgets.PasswordInput( attrs={'class':'form-control'} ) ) re_password = forms.CharField( label='确认密码', min_length=6, error_messages={ 'required': '密码不能为空', 'min_length': '密码不得少于6位', }, widget=forms.widgets.PasswordInput( attrs={'class': 'form-control'} ) ) phone = forms.CharField( label='手机号', min_length=11, error_messages={ 'required':'手机号不能为空', }, validators=[RegexValidator(r'1[3-9]\d{9}', "手机号码格式不正确")], widget=forms.widgets.TextInput( attrs={"class": "form-control"} ) ) email = forms.CharField( label='邮箱', error_messages={ 'required':'邮箱不能为空', }, validators=[RegexValidator(r'^[a-zA-Z0-9_.-]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*\.[a-zA-Z0-9]{2,6}$', "邮箱格式不正确")], widget=forms.widgets.EmailInput( attrs={"class": "form-control"} ) ) # 全局钩子 用来验证密码和确认密码两个字段是否相等 def clean(self): pwd = self.cleaned_data.get('password') re_pwd = self.cleaned_data.get('re_password') if re_pwd and re_pwd == pwd: return self.cleaned_data else: self.add_error('re_password','两次密码不一致') raise ValidationError('两次密码不一致')
然后再urls.py中写路由
url(r'^register/',views.Register.as_view()),
在views.py中写CBV的视图函数(简单些):
class Register(views.View): def get(self,request): form_obj = RegisterForm() return render(request,'register.html',{'form_obj':form_obj}) def post(self,request): pass
在搭建register的html页面:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>欢迎注册</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form> <div class="form-group"> <label for="{{ from_obj.username.id_for_label }}">{{ form_obj.username.label }}</label> {{ form_obj.username }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label> {{ form_obj.password }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.re_password.id_for_label }}">{{ form_obj.re_password.label }}</label> {{ form_obj.re_password }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.phone.id_for_label }}">{{ form_obj.phone.label }}</label> {{ form_obj.phone }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.email.id_for_label }}">{{ form_obj.email.label }}</label> {{ form_obj.email }} <span class="help-block"></span> </div> <button type="button" class="btn btn-default">注册</button> </form> </div> </div> </div> <script src="/static/js/jquery.js"></script> <script> </script> </body> </html>
等这些简单的都做好了在一步一步往里面补充内容.
views.py代码:
# 注册 class Register(views.View): def get(self,request): form_obj = RegisterForm() return render(request,'register.html',{'form_obj':form_obj}) def post(self,request): res = {'code':0} # print(request.POST) v_code = request.POST.get('v_code','') # print(v_code) # 先进行验证码的校验 if v_code.upper() == request.session.get('v_code'): form_obj = RegisterForm(request.POST) # 验证码正确 if form_obj.is_valid(): #数据校验 print(form_obj.cleaned_data) # 删除不需要的数据 form_obj.cleaned_data.pop('re_password') models.UserInfo.objects.create_user(**form_obj.cleaned_data) # 创建完了,进入登陆 res['msg'] = '/login/' else: #用户填写的信息不正经 res['code'] = 1 res['msg'] = form_obj.errors # 拿到所有的错误信息 else: res['code'] = 2 res['msg'] = '验证码错误' return JsonResponse(res)
html代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>欢迎注册</title> <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.css"> </head> <body> {% csrf_token %} <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form> <div class="form-group"> <label for="{{ from_obj.username.id_for_label }}">{{ form_obj.username.label }}</label> {{ form_obj.username }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label> {{ form_obj.password }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.re_password.id_for_label }}">{{ form_obj.re_password.label }}</label> {{ form_obj.re_password }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.phone.id_for_label }}">{{ form_obj.phone.label }}</label> {{ form_obj.phone }} <span class="help-block"></span> </div> <div class="form-group"> <label for="{{ form_obj.email.id_for_label }}">{{ form_obj.email.label }}</label> {{ form_obj.email }} <span class="help-block"></span> </div> <div class="form-group"> <label for="v_code">验证码</label> <input type="text" id="v-code" class="form-control" style="width: 250px; height:35px;display: inline-block"> <img src="/v_code/" alt=""> <span id="error-p" class="err-text"></span> </div> <button id="reg-btn" type="button" class="btn btn-success">注册</button> </form> </div> </div> </div> <script src="/static/js/jquery.js"></script> <script> $('#reg-btn').click(function () { //取到用户填写的数据 var username = $('#id_username').val(); var pwd = $('#id_password').val(); var re_pwd = $('#id_re_password').val(); var phone = $('#id_phone').val(); var email = $('#id_email').val(); var v_code = $('#v-code').val(); var csrfToken = $("[name='csrfmiddlewaretoken']").val(); //发送请求 $.ajax({ url:'/register/', type:'post', data:{ username:username, password:pwd, re_password:re_pwd, phone:phone, email:email, v_code:v_code, csrfmiddlewaretoken:csrfToken, }, success:function (res) { {# console.log(res);#} //验证码有误 if(res['code'] === 2){ $('#error-p').text(res['msg']) //注册成功 }else if(res.code === 0){ location.href = res.msg //用户信息有误 }else if(res.code === 1){ console.log(res.msg); $.each(res.msg,function (k,v) { $('#id_'+k).next().text(v[0]).parent().addClass('has-error') }) } } }) }); // 每一个input标签获取焦点的时候,把自己下面的span标签内容清空,把父标签的has-error样式移除 $('input.form-control').focus(function () { $(this).next('span').text('').parent().removeClass('has-error') }); $("#v-code").focus(function () { $(this).val('').next().next().text(''); }); </script> </body> </html>
这就是注册的功能。
现在我们需要在注册的功能上加上用户选择头像的功能
这时候我们就需要在html上加上这样一个div
<div class="form-group">
<label for="avatar">头像</label>
<img id="avatar-img" src="/static/img/default.png" alt="" style="height: 80px;width: 80px;margin-left: 15px">
<input type="file" accept="image/*" id="avatar" >
</div>
这样页面上的效果是这样的这必然不是我们想要的,我们想要的是我们点击图片时就可以选择头像。所以最后我们将img标签放在label标签内就可以了。
当我们选择头像时,实现在页面上的预览就需要加上jQuery操作了。
//前端页面实现头像预览 //当用户选中文件之后,也就是头像的input标签有值时触法 $('#avatar').change(function () { //找到用户选中的文件 var file = this.files[0]; //console.log(this.files,typeof this.files); //生成一个读文件的对象 var fr = new FileReader(); //从文件中读取头像文件数据 fr.readAsDataURL(file); //读取文件之后 fr.onload = function () { //将img标签的src更换成我选中的那个文件的地址 $('#avatar-img').attr('src',fr.result) } })
这样就可以了。
虽然在页面上是可以展现出来了,但是我们需要把他发送到后端去,这样发送ajax请求时的jQuery操作就有改变了:
$("#reg-btn").click(function () { // 1. 取到用户填写的数据 var fd = new FormData(); fd.append("username", $("#id_username").val()); fd.append("password", $("#id_password").val()); fd.append("re_password", $("#id_re_password").val()); fd.append("phone", $("#id_phone").val()); fd.append("email", $("#id_email").val()); fd.append("v_code", $("#v-code").val()); fd.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); fd.append('avatar', $("#avatar")[0].files[0]); // 2. 往后端发post请求 $.ajax({ url: '/reg/', type: 'post', data: fd, processData: false, contentType: false, success:function (res) { console.log(res); if (res.code === 2){ // 验证码有错误 $("#error-p").text(res.msg); }else if (res.code === 0){ // 注册成功 location.href = res.msg; }else if (res.code === 1){ console.log(res.msg); // 遍历取出所有的错误提示信息,在页面上展示出来 $.each(res.msg, function (k,v) { $("#id_"+k).next().text(v[0]).parent().addClass('has-error'); }) } } }) });
views,py中注册类就需要接受头像文件:
# 注册 class RegView(views.View): def get(self, request): form_obj = RegisterForm() return render(request, "register.html", {"form_obj": form_obj}) def post(self, request): res = {"code": 0} print(request.POST) # 先进行验证码的校验 v_code = request.POST.get("v_code", "") if v_code.upper() == request.session.get("v_code"): # 验证码正确 form_obj = RegisterForm(request.POST) # 使用form做校验 if form_obj.is_valid(): # 数据有效 # 1. 注册用户 print(form_obj.cleaned_data) # 注意移除不需要的re_password form_obj.cleaned_data.pop("re_password") # 拿到用户上传的头像文件 avatar_file = request.FILES.get("avatar") models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_file) # 登录成功之后跳转到登录页面 res["msg"] = '/login/' else: # 用户填写的数据不正经 res["code"] = 1 res["msg"] = form_obj.errors # 拿到所有字段的错误提示信息 else: res["code"] = 2 res["msg"] = '验证码错误' return JsonResponse(res)
现在我们将这个头像展现在登陆之后的index页面中去
页面中的用户名用{{ request.user.username }}显示,头像用{{ request.user.avatar }} 显示,但是在显示头像时,需要配置setting文件,和urls.py文件
在settings文件中配置:
#用户上传的文件配置 MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR,'media')
urls.py文件中配置:
from django.views.static import serve from django.conf import settings #给用户上传文件配置一个处理的路由 url(r'^media/(?P<path>.*)',serve,{'document_root':settings.MEDIA_ROOT}),
头像显示时 “/media/{{ request.user.avatar }} " 表示。这样是告诉django从/media/的目录找,这样头像就能显示出来了.