form组件和ajax实现的注册
########################################
1、Form组件
我们一般写Form的时候都是把它写在views视图里面,那么他和我们的视图函数也不影响,我们可以吧它单另拿出来,在应用下面建一个forms.py的文件来存放
#######################################
2、局部钩子函数 def clean_username(self): username = self.cleaned_data.get("username") valid = models.UserInfo.objects.filter(username = username).first() if valid: raise ValidationError("用户名已存在") return username
#########################################
3、全局钩子函数 #自定义全局钩子:验证两次密码是否一致 def clean(self): if self.cleaned_data.get("password") == self.cleaned_data.get("password_again"): return self.cleaned_data else: raise ValidationError("两次密码不一致")
########################################
可以用下面的方法判断是什么请求 if request.ajax(): #如果ajax请求 if request,method=="POST": #如果是POST请求
######################################
上传文件有一个固定的配置参数media,和static相似 但又不同 步骤如下: - 首先在settings中配置: # ============media配置=============== MEDIA_URL="/media/" #别名 MEDIA_ROOT=os.path.join(BASE_DIR,"app01","media","uploads") #具体路径
- 在url中配置 url(r'^media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT}), 用处: 用处一: ----- avatar = models.FileField(verbose_name='头像', upload_to='avatar', default="/avatar/default.png") 会把接收的文件放在media指代的路径与upload_to的拼接:BASE_DIR+blog+media+uploads+avatar/a.png avatar字段在数据库中保存的是:avatar/a.png 用处二: ------ <img src="/media/avatar/a.png">
###################################################
""" bbs用到的form类 """ from django import forms from django.core.exceptions import ValidationError from blog import models # 定义一个注册的form类 class RegForm(forms.Form): username = forms.CharField( max_length=16, label="用户名", error_messages={ "max_length": "用户名最长16位", "required": "用户名不能为空", }, widget=forms.widgets.TextInput( attrs={"class": "form-control"}, ) ) password = forms.CharField( min_length=6, label="密码", widget=forms.widgets.PasswordInput( attrs={"class": "form-control"}, render_value=True, ), error_messages={ "min_length": "密码至少要6位!", "required": "密码不能为空", } ) re_password = forms.CharField( min_length=6, label="确认密码", widget=forms.widgets.PasswordInput( attrs={"class": "form-control"}, render_value=True, ), error_messages={ "min_length": "确认密码至少要6位!", "required": "确认密码不能为空", } ) email = forms.EmailField( label="邮箱", widget=forms.widgets.EmailInput( attrs={"class": "form-control"}, ), error_messages={ "invalid": "邮箱格式不正确!", "required": "邮箱不能为空", } ) # 重写username字段的局部钩子 def clean_username(self): username = self.cleaned_data.get("username") is_exist = models.UserInfo.objects.filter(username=username) if is_exist: # 表示用户名已注册 self.add_error("username", ValidationError("用户名已存在")) else: return username # 重写email字段的局部钩子 def clean_email(self): email = self.cleaned_data.get("email") is_exist = models.UserInfo.objects.filter(email=email) if is_exist: # 表示邮箱已注册 self.add_error("email", ValidationError("邮箱已被注册")) else: return email # 重写全局的钩子函数,对确认密码做校验 def clean(self): password = self.cleaned_data.get("password") re_password = self.cleaned_data.get("re_password") if re_password and re_password != password: self.add_error("re_password", ValidationError("两次密码不一致")) else: return self.cleaned_data
#############################################
# 注册的视图函数 def register(request): if request.method == "POST": print(request.POST) print("=" * 120) ret = {"status": 0, "msg": ""} form_obj = forms.RegForm(request.POST) print(request.POST) # 帮我做校验 if form_obj.is_valid(): # 校验通过,去数据库创建一个新的用户 form_obj.cleaned_data.pop("re_password") avatar_img = request.FILES.get("avatar") models.UserInfo.objects.create_user(**form_obj.cleaned_data, avatar=avatar_img) ret["msg"] = "/index/" return JsonResponse(ret) else: print(form_obj.errors) ret["status"] = 1 ret["msg"] = form_obj.errors print(ret) print("=" * 120) return JsonResponse(ret) # 生成一个form对象 form_obj = forms.RegForm() print(form_obj.fields) return render(request, "register.html", {"form_obj": form_obj}) # return render(request, "form_test.html", {"form_obj": form_obj}) # 校验用户名是否已被注册 def check_username_exist(request): ret = {"status": 0, "msg": ""} username = request.GET.get("username") print(username) is_exist = models.UserInfo.objects.filter(username=username) if is_exist: ret["status"] = 1 ret["msg"] = "用户名已被注册!" return JsonResponse(ret)
##########################################
from django.conf.urls import url, include from django.contrib import admin from blog import views from django.views.static import serve from django.conf import settings from blog import urls as blog_urls urlpatterns = [ url(r'^reg/', views.register), # 专门用来校验用户名是否已被注册的接口 url(r'^check_username_exist/$', views.check_username_exist), # media相关的路由设置 url(r'^media/(?P<path>.*)$', serve, {"document_root": settings.MEDIA_ROOT}), ]
##########################################
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>欢迎注册</title> <link rel="stylesheet" href="/static/bootstrap/css/bootstrap.min.css"> <link rel="stylesheet" href="/static/mystyle.css"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-md-offset-3"> <form novalidate autocomplete="off" action="/reg/" method="post" class="form-horizontal reg-form" enctype="multipart/form-data"> {% csrf_token %} <div class="form-group"> <label for="{{ form_obj.username.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.username.label }}</label> <div class="col-sm-8"> {{ form_obj.username }} <span class="help-block">{{ form_obj.username.errors.0 }}</span> </div> </div> <div class="form-group"> <label for="{{ form_obj.password.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.password.label }}</label> <div class="col-sm-8"> {{ form_obj.password }} <span class="help-block">{{ form_obj.password.errors.0 }}</span> </div> </div> <div class="form-group"> <label for="{{ form_obj.re_password.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.re_password.label }}</label> <div class="col-sm-8"> {{ form_obj.re_password }} <span class="help-block">{{ form_obj.re_password.errors.0 }}</span> </div> </div> <div class="form-group"> <label for="{{ form_obj.email.id_for_label }}" class="col-sm-2 control-label">{{ form_obj.email.label }}</label> <div class="col-sm-8"> {{ form_obj.email }} <span class="help-block">{{ form_obj.email.errors.0 }}</span> </div> </div> <div class="form-group"> <label class="col-sm-2 control-label">头像</label> <div class="col-sm-8"> <label for="id_avatar"><img id="avatar-img" src="/static/img/default.png" alt=""></label> <input accept="image/*" type="file" name="avatar" id="id_avatar" style="display: none"> <span class="help-block"></span> </div> </div> <div class="form-group"> <div class="col-sm-offset-2 col-sm-10"> <button type="button" class="btn btn-success" id="reg-submit">注册</button> </div> </div> </form> </div> </div> </div> <script src="/static/jquery-3.3.1.js"></script> <script src="/static/bootstrap/js/bootstrap.min.js"></script> <script> // 找到头像的input标签绑定change事件 $("#id_avatar").change(function () { // 1. 创建一个读取文件的对象 var fileReader = new FileReader(); // 取到当前选中的头像文件 // console.log(this.files[0]); // 读取你选中的那个文件 fileReader.readAsDataURL(this.files[0]); // 读取文件是需要时间的 fileReader.onload = function () { // 2. 等上一步读完文件之后才 把图片加载到img标签中 $("#avatar-img").attr("src", fileReader.result); }; }); // AJAX提交注册的数据 $("#reg-submit").click(function () { // 取到用户填写的注册数据,向后端发送AJAX请求 var formData = new FormData(); formData.append("username", $("#id_username").val()); formData.append("password", $("#id_password").val()); formData.append("re_password", $("#id_re_password").val()); formData.append("email", $("#id_email").val()); formData.append("avatar", $("#id_avatar")[0].files[0]); formData.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val()); $.ajax({ url: "/reg/", type: "post", processData: false, // 告诉jQuery不要处理我的数据 contentType: false, // 告诉jQuery不要设置content类型 data: formData, success:function (data) { if (data.status){ // 有错误就展示错误 // console.log(data.msg); // 将报错信息填写到页面上 $.each(data.msg, function (k,v) { // console.log("id_"+k, v[0]); // console.log($("#id_"+k)); $("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error"); }) }else { // 没有错误就跳转到指定页面 location.href = data.msg; } } }) }); // 将所有的input框绑定获取焦点的事件,将所有的错误信息清空 $("form input").focus(function () { $(this).next().text("").parent().parent().removeClass("has-error"); }); // 给username input框绑定一个失去焦点的事件,失去焦点之后就校验用户名是否已被注册 {#$("#id_username").blur(function () {#} $("#id_username").on("input", function () { // 取到用户填写的值 var username = $(this).val(); // 发请求 $.ajax({ url: "/check_username_exist/", type: "get", data: {"username": username}, success: function (data) { if (data.status){ // 用户名已被注册 $("#id_username").next().text(data.msg).parent().parent().addClass("has-error"); } } }) }) </script> </body> </html>
###########################################################
技术改变命运