基于form组件的注册 + 基于Ajax的注册

基于form组件的注册

urls.py

from django.contrib import admin
from django.urls import path

from blog import views
urlpatterns = [
    path('admin/', admin.site.urls),

    #注册
    path('register/', views.register),
    

]

views.py

#注册视图函数
def register(request):
    form_obj = forms.RegForm()
    if request.method == "POST":
        form_obj = forms.RegForm(request.POST)
        #帮我做校验
        if form_obj.is_valid():
            #校验通过,去数据库创建一个新的用户
            # 所以经过校验的数据都保存在  form_obj.cleaned_data  (一个大 字典 中)
            # print(form_obj.cleaned_data)    #{'name': '某某某', 'pwd': '1234567', 're_pwd': '1234567'}
            del form_obj.cleaned_data["re_password"]  # 删除字典中的 re_pwd 因为数据库中没有这个属性
            models.UserInfo.objects.create_user(**form_obj.cleaned_data)
            return HttpResponse("注册成功!")
        else:
            print(form_obj.errors)
            return HttpResponse("出错啦!")


    return render(request, 'register.html',{"form_obj":form_obj})

register.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
    <style>
        .container {
            margin-top: 100px;
        }
{#        头像图片#}
        #avatar_img {
            width: 80px;
            height: 50px;
        }
{#        隐藏选择图片的按钮#}
        #id_avatar {
            display: none;
        }
    </style>
</head>
<body>


<div class="container">
    <div class="row">
        <div class="col-md-offset-3 col-md-6">
            <form action="" method="post" class="form-horizontal" enctype="multipart/form-data">
                {% csrf_token %}
{#                用户名#}
                <div class="form-group {% if form_obj.username.errors.0 %}has-error{% endif %}">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.username }}
                        <span class="help-block">{{ form_obj.username.errors.0 }}</span>
                    </div>
                </div>
{#                密码#}
                <div class="form-group {% if form_obj.password.errors.0 %}has-error{% endif %}">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.password }}
                        <span class="help-block">{{ form_obj.password.errors.0 }}</span>
                    </div>
                </div>
{#                确认密码#}
                <div class="form-group {% if form_obj.re_password.errors.0 %}has-error{% endif %}">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.re_password.id_for_label }}">{{ form_obj.re_password.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.re_password }}
                        <span class="help-block">{{ form_obj.re_password.errors.0 }}</span>
                    </div>
                </div>
{#                邮箱#}
                <div class="form-group {% if form_obj.email.errors.0 %}has-error{% endif %}">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.email.id_for_label }}">{{ form_obj.email.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.email }}
                        <span class="help-block">{{ form_obj.email.errors.0 }}</span>
                    </div>
                </div>
{#                头像   因为在forms.py中没有这个input选项,只能自己写#}
                <div class="form-group">
                    <label class="col-sm-2 control-label">头像</label>
                    <div class="col-sm-10">
{#                        实现了点击图片相当于点击 选择头像按钮#}
                        <label for="id_avatar"><img id="avatar_img" src="/static/img/girl.png" alt=""></label>
                        <input type="file" name="avatar" id="id_avatar">
                    </div>
                </div>

                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-2">
                        <input type="submit" value="注册" class="btn btn-success">
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
<script src="{% static 'jquery-3.2.1.min.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
</body>
</html>

自己写的forms.py

'''
BBS 用到的form类
'''

from django import forms

#定义一个注册的form类
class RegForm(forms.Form):
    username = forms.CharField(
        max_length=16,
        label="用户名",
        widget=forms.widgets.TextInput(
            attrs={"class": "form-control"}
        ),
        error_messages={
            "max_length":"用户名最长16位",
            "require":"用户名不能为空"
        }
    )
    password = forms.CharField(
        min_length=6,
        label="密码",
        error_messages={
            "min_length": "密码至少6位",
            "require": "密码不能为空"
        },
        widget=forms.widgets.PasswordInput(
            render_value=True,
            attrs={"class":"form-control"}
        )
    )
    re_password = forms.CharField(
        min_length=6,
        label="确认密码",
        error_messages={
            "require": "确认密码不能为空"
        },
        widget=forms.widgets.PasswordInput(
            render_value=True,
            attrs={"class": "form-control"}
        )
    )
    email = forms.EmailField(
        label="邮箱",
        error_messages={
            "require": "邮箱不能为空"
        },
        widget=forms.widgets.EmailInput(
            attrs={"class": "form-control"}
        )
    )

补充1 

以上注册功能已经实现的差不多了,但是在 选择头像 时,选择的头像不会替换默认的图片

改进方法如下(一个新的知识点):

#给选择图片的input标签绑定事件
<script>
    //找到头像的input标签,绑定change 事件
    $("#id_avatar").on("change",function () {
        //1.创建一个读文件的对象
        var filereader = new FileReader();
        //取到当前选中的头像文件
        console.log(this.files[0]);
        //读取你选中的文件
        filereader.readAsDataURL(this.files[0]);    //读文件是需要事件的(js是异步的)
        //实现等待功能
        filereader.onload = function () {
            //2.等上一步读完文件之后,把图片加载到img标签里面
            $("#avatar_img").attr("src",filereader.result);
        }


    })
</script>

 补充2

检验两次输入的密码是否正确

在forms.py中添加:


from django.core.exceptions import ValidationError
#重写全局的钩子函数,对确认密码做校验
    def clean(self):
        password = self.cleaned_data.get('password')   #注意:一定要使用get来取值,如果直接用字典的方法取值的话,要是为空会报错的
        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

补充3:

判断新创建的用户名是否已经存在:

方法一:

    #在forms.py中添加

    #重写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('用户名已存在!'))

 方法二:

在register.html中添加:

//给input框绑定一个失去焦点的事件,失去焦点就校验用户名是否已被注册
    $("#id_username").on("blur",function () {
        //取到用户填写的值
        var username = $(this).val();
        //发请求
        $.ajax({
            url:"/check_username_exist/",
            type:"get",
            data:{"username":username},
            success:function (arg) {
                if(arg.status){
                    //用户名已被注册
                    $("#id_username").next().text(arg.msg).parent().parent().addClass("has-error");
                }
            }
        })
    })

在url.py中添加:

    # 专门用来校验用户名是否已被注册的接口
    path('check_username_exist/', views.check_username_exist),

在views.py中添加:

#校验用户名是否已被注册
def check_username_exist(request):
    res = {"status":0,"msg":""}
    username = request.GET.get("username")
    is_exist = models.UserInfo.objects.filter(username=username)
    if is_exist:
        #用户名已被注册
        res["status"] = 1
        res["msg"] = "用户名已被注册!"
    return JsonResponse(res)

 

 基于Ajax的注册(重点)

其中,urls.py 和 forms.py同上

views.py

from blog import forms,models
from django.shortcuts import render,redirect,HttpResponse

#注册视图函数
def register(request):
    if request.method == "POST":
        res = {"status":0,"msg":""}
        form_obj = forms.RegForm(request.POST)
        #帮我做校验
        if form_obj.is_valid():
            #校验通过,去数据库创建一个新的用户
            # 所以经过校验的数据都保存在  form_obj.cleaned_data  (一个大 字典 中)
            # print(form_obj.cleaned_data)    #{'name': '某某某', 'pwd': '1234567', 're_pwd': '1234567'}
            del form_obj.cleaned_data["re_password"]  # 删除字典中的 re_pwd 因为数据库中没有这个属性
            models.UserInfo.objects.create_user(**form_obj.cleaned_data)
            res["msg"] = "/index/"
            return JsonResponse(res)
        else:
            #print(form_obj.errors)
            #如果有错误
            res["status"] = 1
            res["msg"] = form_obj.errors
            return JsonResponse(res)

    form_obj = forms.RegForm()
    return render(request, 'register.html',{"form_obj":form_obj})

register.html

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <title>注册</title>
    <meta name="viewport" content="width=device-width, initial-scale=1">
    {% load static %}
    <link rel="stylesheet" href="{% static 'bootstrap/css/bootstrap.min.css' %}">
    <style>
        .container {
            margin-top: 100px;
        }
{#        头像图片#}
        #avatar_img {
            width: 80px;
            height: 50px;
        }
{#        隐藏选择图片的按钮#}
        #id_avatar {
            display: none;
        }
    </style>
</head>
<body>


<div class="container">
    <div class="row">
        <div class="col-md-offset-3 col-md-6">
            <form novalidate action="" method="post" class="form-horizontal" enctype="multipart/form-data">
                {% csrf_token %}
{#                用户名#}
                <div class="form-group">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.username.id_for_label }}">{{ form_obj.username.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.username }}
                        <span class="help-block"></span>
                    </div>
                </div>
{#                密码#}
                <div class="form-group">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.password.id_for_label }}">{{ form_obj.password.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.password }}
                        <span class="help-block"></span>
                    </div>
                </div>
{#                确认密码#}
                <div class="form-group">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.re_password.id_for_label }}">{{ form_obj.re_password.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.re_password }}
                        <span class="help-block"></span>
                    </div>
                </div>
{#                邮箱#}
                <div class="form-group">
                    <label class="col-sm-2 control-label"
                           for="{{ form_obj.email.id_for_label }}">{{ form_obj.email.label }}</label>
                    <div class="col-sm-10">
                        {{ form_obj.email }}
                        <span class="help-block"></span>
                    </div>
                </div>
{#                头像#}
                <div class="form-group">
                    <label class="col-sm-2 control-label">头像</label>
                    <div class="col-sm-10">
{#                        实现了点击图片相当于点击 选择头像按钮#}
                        <label for="id_avatar"><img id="avatar_img" src="/static/img/girl.png" alt=""></label>
                        <input type="file" name="avatar" id="id_avatar">
                    </div>
                </div>
{#                注册按钮#}
                <div class="form-group">
                    <div class="col-sm-offset-2 col-sm-2">
                        <input type="button" value="注册" class="btn btn-success" id="reg_button">
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
<script src="{% static 'jquery-3.2.1.min.js' %}"></script>
<script src="{% static 'bootstrap/js/bootstrap.min.js' %}"></script>
<script src="{% static 'setupajax.js' %}"></script>
<script>
    //找到头像的input标签,绑定change 事件
    $("#id_avatar").on("change",function () {
        //1.创建一个读文件的对象
        var filereader = new FileReader();
        //取到当前选中的头像文件
        console.log(this.files[0]);
        //读取你选中的文件
        filereader.readAsDataURL(this.files[0]);    //读文件是需要事件的(js是异步的)
        //实现等待功能
        filereader.onload = function () {
            //2.等上一步读完文件之后,把图片加载到img标签里面
            $("#avatar_img").attr("src",filereader.result);
        }
    });

    //用Ajax提交注册的数据           重点
    $("#reg_button").on("click",function () {
        //取到用户填写的注册信息,向后端发送Ajax请求
        $.ajax({
            url:"/register/",
            type:"post",
            data:{
                username:$("#id_username").val(),
                password:$("#id_password").val(),
                re_password:$("#id_re_password").val(),
                email:$("#id_email").val()
            },
            success:function (arg) {
                if(arg.status){
                    //有错误就展示错误
                    console.log(arg.msg);
                    //将报错信息填写到页面上
                    $.each(arg.msg,function (k,v) {
{#                        console.log("id_"+k,v[0]);#}
                        //console.log($("#id_"+k))
                        //找到对应input标签下面的 span标签 并添加内容
                        $("#id_"+k).next("span").text(v[0]);
                        $("#id_"+k).parent().parent().addClass("has-error")
                    })
                }else{
                    //没有就跳转到指定页面
                    location.href = arg.msg;
                }
            }
        })
    });
    //将所有的input框绑定获取焦点的事件,并将所有的错误信息清空
    $("form input").on("focus",function () {
        //this指的是当前点击的input标签
        //同时实现两个功能 1.当input框中聚焦点时,清空错误信息   2.把框的颜色 变回原来的颜色
        $(this).next().text("").parent().parent().removeClass("has-error");
    })
</script>
</body>
</html>

补充:

但是这个还不完美,因为  头像还没有上传

补充如下:

views.py修改后

#注册视图函数
def register(request):
    if request.method == "POST":
        res = {"status":0,"msg":""}
        form_obj = forms.RegForm(request.POST)
        #帮我做校验
        if form_obj.is_valid():
            #校验通过,去数据库创建一个新的用户
            # 所以经过校验的数据都保存在  form_obj.cleaned_data  (一个大 字典 中)
            # print(form_obj.cleaned_data)    #{'name': '某某某', 'pwd': '1234567', 're_pwd': '1234567'}
            del form_obj.cleaned_data["re_password"]  # 删除字典中的 re_pwd 因为数据库中没有这个属性
            # 要自己拿头像数据  必须自己去拿 头像数据并上传到数据库
            avatar_img = request.FILES.get('avatar')
            models.UserInfo.objects.create_user(**form_obj.cleaned_data,avatar=avatar_img)
            res["msg"] = "/index/"
            return JsonResponse(res)
        else:
            # print(form_obj)
            #如果有错误
            res["status"] = 1
            res["msg"] = form_obj.errors
            return JsonResponse(res)

    form_obj = forms.RegForm()
    return render(request, 'register.html',{"form_obj":form_obj})

register.html修改后

//注意:是局部修改

//用Ajax提交注册的数据
    $("#reg_button").on("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]);
{#        console.log(formData);#}
        $.ajax({
            url:"/register/",
            type:"post",
{#            使用Ajax传文件必须加上下面两行数据#}
            processData:false,
            contentType:false,
{#            使用Ajax传文件时,data必须是 FormData 类型#}
            data:formData,
            success:function (arg) {
                if(arg.status){
                    //有错误就展示错误
{#                    console.log(arg.msg);#}
                    //将报错信息填写到页面上
                    $.each(arg.msg,function (k,v) {
{#                        console.log("id_"+k,v[0]);#}
                        //console.log($("#id_"+k))
                        //找到对应input标签下面的 span标签 并添加内容
{#                        $("#id_"+k).next("span").text(v[0]);#}
{#                        $("#id_"+k).parent().parent().addClass("has-error");#}
                        //相当于上面两步
                        $("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
                    })
                }else{
                    //没有就跳转到指定页面
                    location.href = arg.msg;
                }
            }
        })
    });

使用Ajax上传包含文件时的注意事项:

1.使用Ajax传文件必须加上下面两行数据(填写在    $.ajax({})    中) 

processData:false,

contentType:false,

2.使用Ajax传文件时,data必须是 FormData 类型

如:

    //用Ajax提交注册的数据
    $("#reg_button").on("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]);
{#        console.log(formData);#}
        $.ajax({
            url:"/register/",
            type:"post",
{#            使用Ajax传文件必须加上下面两行数据#}
            processData:false,
            contentType:false,
{#            使用Ajax传文件时,data必须是 FormData 类型#}
            data:formData,
            success:function (arg) {
                if(arg.status){
                    //有错误就展示错误
{#                    console.log(arg.msg);#}
                    //将报错信息填写到页面上
                    $.each(arg.msg,function (k,v) {
{#                        console.log("id_"+k,v[0]);#}
                        //console.log($("#id_"+k))
                        //找到对应input标签下面的 span标签 并添加内容
{#                        $("#id_"+k).next("span").text(v[0]);#}
{#                        $("#id_"+k).parent().parent().addClass("has-error");#}
                        //相当于上面两步
                        $("#id_"+k).next("span").text(v[0]).parent().parent().addClass("has-error");
                    })
                }else{
                    //没有就跳转到指定页面
                    location.href = arg.msg;
                }
            }
        })
    });

小知识:

 js中each的使用:

var obj = {"name":"小娜","age":18}

$.each(obj,function(k,v){
    console.log(k,v);
})


>>>    name   小娜
           age      18


#要注意格式

 js中$("...").on(" xxx  ",function(){})中xxx的介绍:

最常见的几种使用:

1. click 
    在点击后立刻执行

2. focus
    聚焦后立刻执行

3. blur
    失去焦点后立刻执行

4. change
    改变后立刻执行
原文地址:https://www.cnblogs.com/liujie12/p/12714862.html