Web框架开发-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("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:隐藏了不占用空间

 

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  

步骤如下:

- 首先在settings中配置:

# 与用户上传相关的配置
MEDIA_ROOT = os.path.join(BASE_DIR, "media")    # 具体路径
MEDIA_URL = "/media/"   # 别名

- 在路由里面配置:

 # media配置:
    re_path(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").change(function () {
            var ele_file = $(this)[0].files[0];     // 当前选中的文件
            // 获取文件对象的路径
            var reader = new FileReader();
            reader.readAsDataURL(ele_file);     // 对应找到打开的url
            console.log(ele_file)
            // 修改img的src属性,src=文件对象的路径
            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)
                            }

  

二、具体实现注册操作

url.py

 url(r'^register/$', views.register),
    # media配置:
    re_path(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})
        # return render(request, "reg.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")
            models.UserInfo.objects.create_user(username=username, password=password, tel=tel, avatar_img=avatar_img)
            regresponse["user"] = username
        else:
            regresponse["msg_errors"] = form.errors
        return HttpResponse(json.dumps(regresponse))
views.py

forms.py

class RegisterForm(Form):
    username = fields.CharField(
        required=True,
        max_length=16,
        min_length=3,
        error_messages={
            "required": "用户名不能为空!",
            "max_length": "长度不能大于16",
            "max_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",
            "max_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",
            "max_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(self):
    if self.cleaned_data.get("password") == self.cleaned_data("password_again"):
        return self.cleaned_data
    else:
        raise ValidationError("两次密码不一致")
forms.py

register.html

  1 <!DOCTYPE html>
  2 <html lang="en">
  3 <head>
  4     <meta charset="UTF-8">
  5     <title>Title</title>
  6     <link rel="stylesheet" href="/static/bootstrap-3.3.7/css/bootstrap.css">
  7     <link rel="stylesheet" href="/static/css/res.css">
  8     <script src="/static/js/jquery-3.3.1.js"></script>
  9     <script src="/static/bootstrap-3.3.7/js/bootstrap.min.js"></script>
 10     <script src="https://cdn.bootcss.com/jquery-cookie/1.4.1/jquery.cookie.js"></script>
 11 
 12 </head>
 13 <body>
 14 {#导航条#}
 15 <nav class="navbar navbar-inverse navbar-fixed-top">
 16     <div class="container pull-left">
 17         <!-- Brand and toggle get grouped for better mobile display -->
 18         <div class="navbar-header">
 19             <button type="button" class="navbar-toggle collapsed" data-toggle="collapse"
 20                     data-target="#bs-example-navbar-collapse-1" aria-expanded="false">
 21                 <span class="sr-only">Toggle navigation</span>
 22                 <span class="icon-bar"></span>
 23                 <span class="icon-bar"></span>
 24                 <span class="icon-bar"></span>
 25             </button>
 26             <a class="navbar-brand" href="#">博客园</a>
 27         </div>
 28 
 29         <!-- Collect the nav links, forms, and other content for toggling -->
 30         <div class="collapse navbar-collapse" id="bs-example-navbar-collapse-1">
 31             <ul class="nav navbar-nav">
 32                 <li class="active c1"><a href="#">首页 <span class="sr-only">(current)</span></a></li>
 33                 <li class="active c1"><a href="#">登录</a></li>
 34                 <li class="active c1"><a href="#">注册</a></li>
 35                 <li class="active c1"><a href="#">帮助</a></li>
 36             </ul>
 37         </div><!-- /.navbar-collapse -->
 38     </div><!-- /.container-fluid -->
 39 </nav>
 40 <h2>注册新用户</h2>
 41 <hr>
 42 <div class="container">
 43     <div class="row left">
 44         <div class="col-md-6 col-md-offset-1">
 45             <form action="/register/" method="post" novalidate enctype="multipart/form-data">
 46                 {% csrf_token %}
 47                 <div class="form-group">
 48                     <label for="username" class="control-label">用户名:</label>
 49                     <div>{{ form.username }}<span></span></div>
 50                 </div>
 51                 <div class="form-group">
 52                     <label for="password" class="control-label">密码:</label>
 53                     <div>{{ form.password }}<span></span></div>
 54                 </div>
 55                 <div class="form-group">
 56                     <label for="password" class="control-label">确认密码:</label>
 57                     <div>{{ form.password_again }}<span></span></div>
 58                 </div>
 59                 <div class="form-group">
 60                     <label for="Email" class="control-label">邮箱:</label>
 61                     <div>{{ form.email }}<span></span></div>
 62                 </div>
 63                 <div class="form-group">
 64                     <label for="tel" class="control-label">手机号码:</label>
 65                     <div>{{ form.tel }}<span></span></div>
 66                 </div>
 67                 <div class="form-group">
 68                     <label for="avatar" class="control-label">头像:</label>
 69                     <img src="/static/image/default.png" alt="" class="avatar_img">
 70                     <input type="file" id="avatar" name="avatar_file" class="avatar_file">
 71                 </div>
 72                 <button type="button" class="btn btn-primary registr_btn">注册</button><span class="error"></span>
 73             </form>
 74         </div>
 75     </div>
 76     <div class="right">
 77 {#        <img src="/static/image/lufei.jpg" alt="">#}
 78     </div>
 79 
 80 </div>
 81 <script>
 82     $(function () {
 83         // 给注册按钮添加事件
 84         $(".registr_btn").click(function () {
 85             var formData = new FormData();
 86             formData.append("username", $("#id_username").val());
 87             formData.append("email", $("#id_email").val());
 88             formData.append("tel", $("#id_tel").val());
 89             formData.append("password", $("#id_password").val());
 90             formData.append("password_again", $("#id_password_again").val());
 91             formData.append("avatar_img", $("#avatar")[0].files[0]);
 92 
 93 
 94             $(".pull-right").html("");
 95             $(".pull-right").parent().removeClass("has-error");
 96             $.ajax({
 97                 url:"/register/",
 98                 type: "post",
 99                 headers: {"X-CSRFToken": $.cookie('csrftoken')},
100                 data:formData,
101                 contentType:false,
102                 processData:false,
103                 success:function (data) {
104 
105                     var data = JSON.parse(data);
106                     if (data["user"]){
107                         $(".error").html("注册成功")
108                         window.location.href="/login/";
109 
110                     }
111                     else {
112                         // 先清除错误信息
113 
114                         console.log(data.msg_errors);   // 拿到的是所有的错误信息
115                         $.each(data.msg_errors, function (field, error_list) {
116                             console.log(field, error_list);
117                             $span = $("<span>");
118                             $span.addClass("pull-right").css("color", "red");
119 
120                             $span.html(error_list[0]);
121                                 $("#id_" + field).after($span).parent().addClass("has-error");
122                                  // 错误信息5秒消失
123                                 setTimeout(function () {
124                                     $(".pull-right").text("")
125 
126                                 }, 5000);
127 
128                             if (field=="__all__"){
129                                 $("#id_password_again").after($span);
130                             }
131 
132 
133 
134 
135 
136 
137 
138 
139                         });
140                     }
141 
142                 }
143             })
144         });
145 
146         // 头像预览
147         $("#avatar").change(function () {
148             var ele_file = $(this)[0].files[0];     // 当前选中的文件
149             // 获取文件对象的路径
150             var reader = new FileReader();
151             reader.readAsDataURL(ele_file);     // 对应找到打开的url
152             console.log(ele_file)
153             // 修改img的src属性,src=文件对象的路径
154             reader.onload = function () {
155                 {# 方式一 #}
156                 $(".avatar_img").attr("src", this.result);  // this.result上上面找到的url
157                 {#  方式二 #}
158                 {#                 $(".avatar_img")[0].src=this.result; //设置图片属性#}
159 
160             }
161 
162         })
163 
164 
165 
166     })
167 </script>
168 </body>
169 </html>
register.html

reg.css

 1 .c1 {
 2     margin-right: 10px;
 3 }
 4 
 5 h2 {
 6     margin-top: 100px;
 7     margin-left: 280px;
 8 }
 9 .left{
10     position: relative;
11 }
12 .right{
13     width: 270px;
14     height: 294px;
15     position: absolute;
16     top: 197px;
17     left: 886px;
18 }
19 .registr_btn{
20     width: 100px;
21     margin-left: 200px;
22 }
23 .avatar{
24     display: none;
25 }
26 .avatar_img,.avatar_file{
27     position: absolute;
28     width: 60px;
29     height: 60px;
30 
31     left: 60px;
32 }
33 .avatar_file{
34     opacity: 0;
35 }
36 
37 .error {
38     color: red;
39     margin-left: 10px;
40 }
res.css

效果截图

 

  

posted @ 2018-10-16 17:16  芳姐  阅读(206)  评论(0编辑  收藏  举报