1. 程式人生 > >Django 【第十七篇】使用Form組件和Ajax實現用戶註冊

Django 【第十七篇】使用Form組件和Ajax實現用戶註冊

紅色 abs form 實現 效果 郵箱 具體實現 addclass 增加

一、註冊相關的知識點

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("兩次密碼不一致")

4、 jQuery的屬性操作相關的

attr:
    一個參數是獲取屬性的值,兩個參數是設置屬性值
removeAttr(屬性名):
    刪除屬性值
prop:
    適應於屬性的返回值是布爾類型的(單選,反選,取消的例子)
removePorp:
    刪除屬性的值

5、循環的兩種方式:

$.each(數組/對象,function(i,v){})
$("div").each(function(i,v){})

6、css中的三種隱藏:

1、display:none  隱藏所有內容
2、visibility:hidden 隱藏內容 3、overflow:hidden 隱藏溢出內容 三者都是用來隱藏的: 區別在於: visibility雖然隱藏了,但是被隱藏的內容依然占據這空間,這段隱藏了的內容卻保留空間的位置會在網頁中顯示空白
而display:隱藏了不占用空間 我們在註冊的時候不用display:none,不然選擇文件的那個功能就沒有了,我們可以吧透明度

7、提交二進制數據用FormData

var formData=new FormData();
formData.append("username",$("#id_username").val()); 
formData.append("email",$("#id_email").val()); formData.append("tel",$("#id_tel").val());
formData.append("password",$("#id_password").val()); formData.append("password_again",$("#id_password_again").val()); formData.append("avatar_img",$("#avatar")[0].files[0]);

記得要加上

contentType:false
processData:false

8、可以用下面的方法判斷是什麽請求

if request.ajax():    #如果ajax請求
if request,method=="POST":   #如果是POST請求

9、上傳文件有一個固定的配置參數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">

如果上傳成功會把圖片自動保存在這裏

技術分享圖片

10、頭像圖片預覽

   //頭像預覽
        $(".avatar_file").change(function () {
            var ele_file = $(this)[0].files[0]; //當前選中的文件
            var reader = new FileReader();
            reader.readAsDataURL(ele_file); //對應找到打開的url
            reader.onload=function () {
{#                方式一#}
                $(".avatar_img").attr("src",this.result) ; //this.result是上面找到的url
{#                方式二#}
{#                 $(".avatar_img")[0].src=this.result; //設置圖片屬性#}
            }
        })

11、form自動生成的錯誤信息

當你定義了全局鉤子的時候,而且正好出現你的那個全局鉤子函數中的錯(比如兩次密碼輸入不一致),這樣你打印錯誤信息的時候

會有一個__all__對象,這個就是你設置的全局鉤子生成的。

技術分享圖片

所以還要單獨判斷一下,現在全局鉤子只有一個,你可以這樣判斷,但是,當全局鉤子多的時候就得一個一個分開來判斷

  if (i=="__all__"){
        $("#id_password_again").after($span)
   }

二、具體實現註冊操作

urls.py

from django.conf.urls import url
from django.contrib import admin
from app01 import views
from django.conf import settings
from django.views.static import serve
urlpatterns = [
    url(r‘^admin/‘, admin.site.urls),
    url(r‘^login/$‘, views.login),
    url(r‘^index/$‘, views.index),
    url(r‘^get_vaildCode_img/$‘, views.get_vaildCode_img),
    url(r‘^log_out/$‘, views.log_out),

    url(r‘^register/$‘, views.register),
    url(r‘^media/(?P<path>.*)$‘, serve, {‘document_root‘: settings.MEDIA_ROOT}),
]

  

views.py

def register(request):
    if request.method=="GET":
        form = RegisterForm()
        return render(request,"register.html",{"form":form})
    else:
        form = RegisterForm(data=request.POST)
        regresponse = {"user":None,"msg_errors":None}
        if form.is_valid():
            username = form.cleaned_data.get("username")
            password = form.cleaned_data.get("password")
            tel = form.cleaned_data.get("tel")
            avatar_img = request.FILES.get("avatar_img")
            print(">>>",username,password,tel)
            models.UserInfo.objects.create_user(username = username,password=password,tel=tel,avatar=avatar_img)
            regresponse["user"] = username
        else:
            print("form.errors",form.errors)
            regresponse["msg_errors"]=form.errors
        return HttpResponse(json.dumps(regresponse))

  

forms.py

#!usr/bin/env python
# -*- coding:utf-8 -*-
from app01 import models
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import ValidationError
from django.core.validators import RegexValidator
class RegisterForm(Form):
    username = fields.CharField(
        required=True,
        max_length=16,
        min_length=3,
        error_messages={
            "required": "用戶名不能為空",
            "max_length": "長度不能大於16",
            "min_length": "長度不能小於3",
        },
        widget=widgets.TextInput({"placeholder":"請您輸入用戶名","class":"form-control"})
    )
    password = fields.CharField(
        required=True,
        max_length=16,
        min_length=3,
        error_messages={
            "required": "密碼不能為空",
            "max_length": "長度不能大於16",
            "min_length": "長度不能小於3",
        },
        widget=widgets.PasswordInput({"placeholder":"請您輸入數字與字母組合的密碼","class":"form-control"})
    )
    password_again = fields.CharField(
        required=True,
        max_length=16,
        min_length=3,
        error_messages={
            "required": "密碼不能為空",
            "max_length": "長度不能大於16",
            "min_length": "長度不能小於3",
        },
        widget=widgets.PasswordInput({"placeholder": "請您再次輸入密碼", "class": "form-control"})
    )
    email = fields.EmailField(
        required=True,
        error_messages={
            "required":"郵箱不能為空",
            "invalid":"郵箱格式有誤"
        },
        widget = widgets.EmailInput({"placeholder": "請輸入您的郵箱", "class": "form-control"})
    )
    tel = fields.CharField(
        required=True,
        max_length=11,
        min_length=11,
        error_messages={
            "required":"手機號碼不能為空",
            "max_length":"長度必須是11位,請你正確輸入",
            "min_length":"長度必須是11位,請你正確輸入",
        },
        validators=[RegexValidator("\d+","密碼只能是數字")],
        widget=widgets.TextInput({"placeholder": "請您輸入你的電話,要求11位哦", "class": "form-control"})
    )

    #自定義用戶名驗證:局部鉤子
    def clean_username(self):
        username = self.cleaned_data.get("username")
        valid = models.UserInfo.objects.filter(username = username).first()
        if valid:
            raise ValidationError("用戶名已存在")
        return username
    #自定義密碼驗證:
    def clean_password(self):
        password = self.cleaned_data.get("password")
        if password.isdigit():
            raise ValidationError("密碼不能是純數字")
        else:
            return password
    #自定義全局鉤子:驗證兩次密碼是否一致
    def clean(self):
        if self.cleaned_data.get("password") == self.cleaned_data.get("password_again"):
            return self.cleaned_data
        else:
            raise  ValidationError("兩次密碼不一致")

  

template

register.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width">
    <title>Title</title>
    <link rel="stylesheet" href="/static/bootstrap-3.3.7-dist/css/bootstrap.min.css">
    <link rel="stylesheet" href="/static/css/reg.css">
</head>
<body>
{#導航條#}
<nav class="navbar navbar-inverse navbar-fixed-top">
    <div class="container pull-left">
        <!-- Brand and toggle get grouped for better mobile display -->
        <div class="navbar-header">
            <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
                    data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
                <span class="sr-only">Toggle navigation</span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
                <span class="icon-bar"></span>
            </button>
            <a class="navbar-brand" href="#">博客園</a>
        </div>

        <!-- Collect the nav links, forms, and other content for toggling -->
        <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
            <ul class="nav navbar-nav">
                <li class="active c1"><a href="#">首頁 <span class="sr-only">(current)</span></a></li>
                <li class="active c1"><a href="#">登錄</a></li>
                <li class="active c1"><a href="#">註冊</a></li>
                <li class="active c1"><a href="#">幫助</a></li>
            </ul>
        </div><!-- /.navbar-collapse -->
    </div><!-- /.container-fluid -->
</nav>
<h2>註冊新用戶</h2>
<hr>
<div class="container">
    <div class="row left">
        <div class="col-md-6 col-md-offset-1">
            <form action="/register/" method="post" novalidate enctype="multipart/form-data">
                {% csrf_token %}
                 <div class="form-group">
                    <label for="password" class="control-label">用戶名:</label>
                    <div>{{ form.username }}<span></span></div>
                </div>
                <div class="form-group">
                    <label for="password" class="control-label">密碼:</label>
                    <div>{{ form.password }}<span></span></div>
                </div>
                <div class="form-group">
                    <label for="password" class="control-label">確認密碼:</label>
                    <div>{{ form.password_again }}<span></span></div>
                </div>
                <div class="form-group">
                    <label for="email" class="control-label">郵箱:</label>
                    <div>{{ form.email }}<span></span></div>
                </div>
                <div class="form-group">
                    <label for="tel" class="control-label">手機號:</label>
                    <div>{{ form.tel }}<span></span></div>
                </div>
                <div class="form-group avatar">
                    <label for="avatar">頭像:</label>
                    <img src="/static/image/default.png"  class="avatar_img">
                    <input type="file" id="avatar" name="avatar_file" class="avatar_file">
                </div>
                <button type="button" class="btn btn-primary registr_btn">註冊</button><span class="xxx"></span>
            </form>
        </div>
    </div>
    <div class="right">
        <img src="/static/image/rigth.png" >
    </div>
</div>

<script src="/static/jquery-3.2.1.min.js"></script>
<script src="/static/bootstrap-3.3.7-dist/js/bootstrap.min.js"></script>
<script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
<script>
    $(function () {
        //給註冊按鈕增加事件
        $(".registr_btn").click(function () {
             var formData=new FormData();
            formData.append("username",$("#id_username").val());
            formData.append("email",$("#id_email").val());
            formData.append("tel",$("#id_tel").val());
            formData.append("password",$("#id_password").val());
            formData.append("password_again",$("#id_password_again").val());
            formData.append("avatar_img",$("#avatar")[0].files[0]);
            console.log("=========",formData);

            //先清除錯誤信息
            $(".pull-right").html("");
            $(".pull-right").parent().removeClass("has-error");
            $.ajax({
                url:"/register/",
                type:"POST",
                headers: {"X-CSRFToken": $.cookie(‘csrftoken‘)},
                data:formData,
                contentType:false,
                processData:false,
                success:function (data) {
{#                    console.log(data);#}
                    var data = JSON.parse(data);
                    if(data["user"]){  //或者也可以用data.user
                        $(".xxx").html("註冊成功");
                        window.location.href="/login/";
                    }
                    else {
                        console.log(data.msg_errors);  //拿到的是所有的錯誤信息
                        $.each(data.msg_errors,function (i,v) {
                            console.log(i,v);
                            $span = $("<span>");//創建一個span標簽,方便提示錯誤信息的時候用
                            $span.addClass("pull-right").css("color","red");  //設置樣式居右並且字體顏色為紅色
                            $span.html(v[0]);//設置span裏面的字體
                              $("#id_"+i).after($span).parent().addClass("has-error");//吧span標簽放到每個input的後面顯示並且讓他的父親變紅,增加一個has-error的類

                             if (i=="__all__"){
                                 $("#id_password_again").after($span)
                             }
                        });
                    }
                }
            })
        });

        //頭像預覽
        $(".avatar_file").change(function () {
            var ele_file = $(this)[0].files[0]; //當前選中的文件
            var reader = new FileReader();
            reader.readAsDataURL(ele_file); //對應找到打開的url
            reader.onload=function () {
{#                方式一#}
                $(".avatar_img").attr("src",this.result) ; //this.result是上面找到的url
{#                方式二#}
{#                 $(".avatar_img")[0].src=this.result; //設置圖片屬性#}
            }
        })
    })
</script>
</body>
</html>

  

reg.css
.c1 {
    margin-right: 10px;
}

h2 {
    margin-top: 100px;
    margin-left: 280px;
}
.left{
    position: relative;
}
.right{
    width: 270px;
    height: 294px;
    position: absolute;
    top: 197px;
    left: 886px;
}
.registr_btn{
    width: 100px;
    margin-left: 200px;
}
.avatar{
    position: relative;
    width: 70px;
    height: 70px;
}
.avatar_img,.avatar_file{
    position: absolute;
    width: 70px;
    height: 70px;
    top: 0;
    left: 46px;
}
.avatar_file{
    opacity: 0;
}

  

效果截圖

技術分享圖片

Django 【第十七篇】使用Form組件和Ajax實現用戶註冊