3- 功能2:基于forms组件和ajax实现注册功能
1、forms组件的注册页面
url
from django.urls import path, re_path from blog import views from django.views.static import serve from cnblog import settings urlpatterns = [ re_path('^login/$', views.login, name='login'), re_path('^get_validCode/$', views.get_validCode, name='get_validCode'), re_path('^index/$', views.index, name='index'), re_path('^register/$', views.register, name='register'), ]
views视图
from blog.myForms import UserForm # froms组件 def register(request): """ 注册页面 :param request: :return: """ form = UserForm return render(request, "blog/register.html", {'form':form})
forms组件
from django import forms from django.forms import widgets from blog.models import UserInfo from django.core.exceptions import ValidationError class UserForm(forms.Form): user = forms.CharField(max_length=32,label="用户名", error_messages={"required": "该字段不能为空"}, 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"}))
模板层
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="">{{ field.label }}</label> {{ field }} </div> {% endfor %} <div class="form-group"> <label for="">头像</label> <img width="60" height="60" src="/static/img/default.jpg" alt="" id="avatar_img" style="margin-left: 20px"> <input type="file" id="avatar"> </div> <input type="button" class="btn btn-success register-btn" value="注册"> </form> </div> </div> </div> </body> </html>
2、头像上传,预览功能
(1)label标签的for属性
(2)头像图像,上传文件input框,一致
(3)头像预览功能:获取input框的图片
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.auto_id }}">{{ field.label }}</label> {{ field }} </div> {% endfor %} <div class="form-group"> <label for="avatar">头像 <img width="60" height="60" src="/static/img/default.jpg" alt="" id="avatar_img" style="margin-left: 20px"> <input type="file" id="avatar" style="display: none"> </label> </div> <input type="button" class="btn btn-success register-btn" value="注册"> </form> </div> </div> </div> <script type="text/javascript"> $(function () { $('#avatar').change(function () { //获取用户选中的文件对象 var file_obj = $(this)[0].files[0]; //获取文件对象的路径 var reader = new FileReader(); reader.readAsDataURL(file_obj); //修改img的src属性, src= 文件对象的路径 // $(this).prepend('img').attr("src", reader.result); // 等页面加载完成在执行onload reader.onload = function () { $("#avatar_img").attr("src", reader.result) } }) }) </script> </body> </html>
3、Ajax提交formdata数据
(1)点击注册按钮
注册视图
(2)循环展示错误msg
(3)代码优化:form表单数据序列化append
4、forms组件的局部钩子,全局钩子
5、注册成功,添加数据
(1)模板层 跳转到view视图
(2)view视图层
(3)FieldFile字段
数据库保存的是文件的路径
(2)代码优化
6、media配置
Dajngo有两种静态文件: /static/ : js,css,img /media/ : 用户上传文件
settings配置
# MEDIA配置:与用户上传相关的配置 # 配置1:用户上传头像的文件 MEDIA_ROOT = os.path.join(BASE_DIR, "media") # 配置2:开放media目录给用户 MEDIA_URL = "/media/"
配置1:settings配置media目录
配置2:开放media目录给用户
(3)开放给用户的目录
开放给用户的目录 http://127.0.0.1:8000/static/img/default.jpg http://127.0.0.1:8000/blog/media/avatars/mingren.jpg/
7、完整代码
主url
from django.contrib import admin from django.urls import path, re_path, include urlpatterns = [ path('admin/', admin.site.urls), re_path(r'^blog/', include(('blog.urls', 'blog'))) ]
url
from django.urls import path, re_path from blog import views from django.views.static import serve from cnblog import settings urlpatterns = [ re_path('^login/$', views.login, name='login'), re_path('^get_validCode/$', views.get_validCode, name='get_validCode'), re_path('^index/$', views.index, name='index'), re_path('^register/$', views.register, name='register'), # media配置 re_path(r'^media/(?P<path>.*)/$', serve, {"document_root": settings.MEDIA_ROOT}), ]
注册views视图
from django.shortcuts import render, HttpResponse, redirect from blog.utils.validCode import get_validCode_img # 导入验证码函数 from django.http import JsonResponse # Json数据返回到前端 from django.contrib import auth # 用户认证组件 from blog.models import UserInfo from blog.myForms import UserForm # froms组件 def register(request): """ 注册页面 :param request: :return: """ # if request.method == 'POST': if request.is_ajax(): response = {'user':None, "msg":None} form = UserForm(request.POST) if form.is_valid(): response['user'] = form.cleaned_data.get("user") # 生成一条数据 user = request.POST.get("user") pwd = request.POST.get("pwd") email = request.POST.get("email") avatar_obj = request.FILES.get("avatar") print(avatar_obj) extra_fields = {} if avatar_obj: extra_fields["avatar"] = avatar_obj UserInfo.objects.create_user(username=user, password=pwd, email=email, **extra_fields) """ if avatar_obj: # 快捷键 alt + f7 UserInfo.objects.create_user(username=user, password=pwd, email=email, avatar=avatar_obj) else: UserInfo.objects.create_user(username=user, password=pwd, email=email) """ else: print(form.cleaned_data) print(form.errors) response['msg'] = form.errors return JsonResponse(response) form = UserForm return render(request, "blog/register.html", {'form':form})
注册forms组件
from django import forms from django.forms import widgets from blog.models import UserInfo from django.core.exceptions import ValidationError class UserForm(forms.Form): user = forms.CharField(max_length=32,label="用户名", error_messages={"required": "该字段不能为空"}, 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"})) # 用户名的认证 def clean_user(self): user = self.cleaned_data.get('user') user_obj = UserInfo.objects.filter(username=user).first() if not user_obj: return user else: raise ValidationError('该用户名已经注册') # return ValidationError('该用户名已经注册') # 不能用出现bug # 密码 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: # return ValidationError("两次密码不一致!") raise ValidationError("两次密码不一致!") else: return self.cleaned_data
注册页面模板层
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link rel="stylesheet" href="/static/blog/bs/css/bootstrap.css"> <script src="/static/js/jquery-3.2.1.min.js"></script> </head> <body> <h3>注册页面</h3> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <form id="id_form"> {% csrf_token %} {% for field in form %} <div class="form-group"> <label for="{{ field.auto_id }}">{{ field.label }}</label> {{ field }} <span class="error pull-right" style="color: red"></span> </div> {% endfor %} <div class="form-group"> <label for="avatar">头像 <img width="60" height="60" src="/static/img/default.jpg" alt="" id="avatar_img" style="margin-left: 20px"> <input type="file" id="avatar" style="display: none"> </label> </div> <input type="button" class="btn btn-success register-btn" value="注册"> </form> </div> </div> </div> </body> </html>
注册页面js代码
<script type="text/javascript"> $(function () { $('#avatar').change(function () { //获取用户选中的文件对象 var file_obj = $(this)[0].files[0]; //获取文件对象的路径 var reader = new FileReader(); reader.readAsDataURL(file_obj); //修改img的src属性, src= 文件对象的路径 // $(this).prepend('img').attr("src", reader.result); // 等页面加载完成在执行onload reader.onload = function () { $("#avatar_img").attr("src", reader.result) } }) }); //基于ajax提交数据 $(function () { $('.register-btn').click(function () { //获取数据 var formdata = new FormData(); <!-- formdata.append("user", $('#id_user').val()); formdata.append("pwd", $('#id_pwd').val()); formdata.append("re_pwd", $('#id_re_pwd').val()); formdata.append("email", $('#id_email').val()); formdata.append("csrfmiddlewaretoken", $('[name="csrfmiddlewaretoken"]').val()); --> var request_data = $('#id_form').serializeArray(); $.each(request_data, function (index, data) { formdata.append(data.name, data.value) }); formdata.append("avatar", $("#avatar")[0].files[0]); $.ajax({ url: '', type: 'post', contentType: false, processData: false, data: formdata, success: function (data) { console.log(data); if (data.user) { //注册成功 location.href = "/blog/login" } else { //清空错误信息,和div的样式 $('span.error').html(""); $(".form-group").removeClass("has-error"); //展示error_msg $.each(data.msg, function (field, error_list) { if (field == "__all__") { $('#id_re_pwd').next('span').html(error_list[0]).parent('div').addClass('has-error'); } else { $('#id_' + field).next('span').html(error_list[0]).parent('div').addClass('has-error'); } }) } } }) }) }) </script>
8、总结
基于forms组件和Ajax实现注册功能 # 1 基于forms组件设计注册页面 ---点击头像===点击input ---头像预览: 1 获取用户选中的文件对象 2 获取文件对象的路径 3 修改img的src属性 ,src=文件对象的路径 # 2 错误信息: views: form.erorrs # {"user":[......]} Ajax.success: $.each(data.msg, function (field, error_list) { $("#id_" + field).next().html(error_list[0]); $("#id_" + field).parent().addClass("has-error"); }) # 3 局部钩子和全局钩子校验 user字段不能重复 两次密码不一致 # 4 FileField与ImageFiled class UserInfo(AbstractUser): nid = models.AutoField(primary_key=True) telephone = models.CharField(max_length=11, null=True, unique=True) avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png") avatar_obj=request.FILES.get("avatar") user_obj=UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar=avatar_obj) Dajngo实现: 会将文件对象下载到项目的根目录中avatars文件夹中(如果没有avatar文件夹,Django会自动创建),user_obj的avatar存的是文件的相对路径。 # 5 Media 配置之MEDIA_ROOT: Dajngo有两种静态文件: /static/ : js,css,img /media/ : 用户上传文件 class UserInfo(AbstractUser): nid = models.AutoField(primary_key=True) telephone = models.CharField(max_length=11, null=True, unique=True) avatar = models.FileField(upload_to='avatars/', default="/avatars/default.png") avatar_obj=request.FILES.get("avatar") user_obj=UserInfo.objects.create_user(username=user,password=pwd,email=email,avatar=avatar_obj) 一旦配置了 MEDIA_ROOT=os.path.join(BASE_DIR,"media") Dajngo实现: 会将文件对象下载到MEDIA_ROOT中avatars文件夹中(如果没有avatar文件夹,Django会自动创建),user_obj的avatar存的是文件的相对路径。 # 6 Media 配置之MEDIA_URl: 浏览器如何能直接访问到media中的数据 settings.py: MEDIA_URL="/media/" urls.pt: # media配置: re_path(r"media/(?P<path>.*)$",serve,{"document_root":settings.MEDIA_ROOT})