用户注册与忘记密码邮箱激活

試著忘記壹切 提交于 2020-02-08 11:26:22

 

    Django Forms 实现用户注册    

    分析:用户注册的信息包含了一个用户的帐号、密码、邮箱以及一个图片性质的头像。    
    实现文件上传的相关配置    
用户模型的设计models.py
<wiz_code_mirror>
 
 
 
9
 
 
 
 
 
1
class UserInfo(AbstractUser):
2
    """继承AbstractUser表并向里加几条数据"""
3
    phone = models.CharField(max_length=11, null=True, unique=True, verbose_name="手机号码")
4
    avatar = models.FileField(upload_to="media/avatars", default="static/img/touxiang.jpg", verbose_name="头像")
5
    create_time = models.DateTimeField(auto_now_add=True, verbose_name="用户角色创建时间")
6

7
    class Meta:
8
        verbose_name = "用户"
9
        verbose_name_plural = verbose_name
 
 
settings.py
<wiz_code_mirror>
 
 
 
5
 
 
 
 
 
1
MEDIA_URL = '/media/'
2
MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
3

4
# 继承auth模块
5
AUTH_USER_MODEL = "blog.UserInfo"
 
 

        <form>表单提交实现用户上传文件功能        

简单的文件上传加写入
    html:    
<wiz_code_mirror>
 
 
 
5
 
 
 
 
 
1
<form action="{% url 'register' %}" method="post" enctype="multipart/form-data">
2
    {% csrf_token %}
3
    <input type="file" name="file_obj">
4
    <input type="submit">
5
</form>
 
 
    注意这里文件上传的两要素:    
1、form标签里面的属性enctype="multipart/form-data"
2、input type="file" name="file_obj"
 
    后端接收、写入:    
<wiz_code_mirror>
 
 
 
19
 
 
 
 
 
1
def register(request):
2
    if request.method == "POST":
3
        value = request.FILES.get("file_obj")
4
        with open(value.name, 'wb') as f:    # value.name 给文件起的名字
5
            for line in value:
6
                f.write(line)
7
        return HttpResponse("上传成功")
8
    return render(request, 'register.html')
9

10
---------------用django提供的chunks方法-----------------
11

12
def register(request):
13
    if request.method == "POST":
14
        value = request.FILES.get("file_obj")
15
        with open(value.name, 'wb') as f:
16
            for chunks in request.FILES.get('file_obj').chunks():
17
                f.write(chunks)
18
        return HttpResponse("上传成功")
19
    return render(request, 'register.html')
 
 
用户头像文件的上传与实时预览
 
<wiz_code_mirror>
 
 
 
13
 
 
 
 
 
1
<form class="form-horizontal" method="post" action="{% url 'register' %}" novalidate enctype="multipart/form-data">
2
    {% csrf_token %}
3
    <div class="form-group">
4
        <label class="col-sm-2 control-label">头像</label>
5
        <div class="col-sm-10">
6
            <label for="avatar">
7
                <img src="{% static '/img/touxiang.jpg' %}" id="avatar-img">
8
            </label>
9
            <input type="file" id="avatar" style="display: none" name="file_obj">
10
        </div>
11
    </div>
12
    <input type="submit" class="btn btn-default">
13
</form>
 
 
 
点击头像就能选择要上传的头像了,但是这里并不能实时预览,所以要用JS将选择的图片放到头像位置:详见代码
<wiz_code_mirror>
 
 
 
13
 
 
 
 
 
1
 // 头像预览功能实现
2
// 绑定一个change事件 仅适用于文本域(text field),以及 textarea 和 select 元素。
3
$("#avatar").change(function () {
4
    // 1.创建一个文件读取对象(必须的)
5
    var fileReader = new FileReader();
6
    // 取到当前选中的头像文件为一个对象,所以取值要加0
7
    // console.log(this.files[0]);
8
    fileReader.readAsDataURL(this.files[0]);
9
    fileReader.onload = function () {
10
        // 2.等读取完文件之后在把图片加载到img标签中
11
        $("#avatar-img").attr("src", fileReader.result);
12
    };
13
});
 
 
DjangoForm 字段 forms.py的设计
<wiz_code_mirror>
 
 
 
85
 
 
 
 
 
1
import re
2
from django import forms
3
from django.core.exceptions import ValidationError
4
from app01.models import *
5

6

7
def mobile_validate(value):
8
    """自定义手机号码校验规则"""
9
    # re.compile()
10
    mobile_re = re.compile(r'^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$')
11
    # .match()
12
    if not mobile_re.match(value):
13
        raise ValidationError('手机号码格式错误')
14

15

16
class RegForm(forms.Form):
17
    username = forms.CharField(
18
        max_length=16,
19
        min_length=8,
20
        label="用户名",
21
        error_messages={
22
            "required": "用户名不能为空",
23
            "min_length": "用户名不能小于8位",
24
            "max_length": "用户名不能查过16位",
25
        },
26
        widget=forms.widgets.TextInput(
27
            attrs={"class": "form-control"}
28
        )
29
    )
30
    password = forms.CharField(
31
        max_length=16,
32
        min_length=8,
33
        label="密码",
34
        error_messages={
35
            "required": "用户名不能为空",
36
            "min_length": "用户名不能小于8位",
37
            "max_length": "用户名不能查过16位",
38
        },
39
        widget=forms.widgets.PasswordInput(
40
            attrs={"class": "form-control"}
41
        )
42
    )
43
    re_password = forms.CharField(
44
        max_length=16,
45
        label="确认密码",
46
        error_messages={
47
            "required": "密码不能为空",
48
            "max_length": "密码不能超过16位",
49
        },
50
        widget=forms.widgets.PasswordInput(attrs={
51
            "class": "form-control",
52
        }),
53
    )
54
    mobile = forms.CharField(validators=[mobile_validate, ],
55
                             label="手机号",
56
                             error_messages={'required': '手机不能为空'},
57
                             widget=forms.widgets.TextInput(attrs={'class': "form-control",
58
                                                            'placeholder': u'手机号码'}))
59

60
    # email = forms.CharField(
61
    #     label="邮箱",
62
    #     error_messages={
63
    #         'required': '邮箱不能为空'
64
    #     },
65
    #     widget=forms.widgets.EmailInput(attrs={
66
    #         "class": "form-control",
67
    #     }),
68
    # )
69

70
    def clean_username(self):
71
        username = self.cleaned_data.get("username", "")
72
        if UserInfo.objects.filter(username=username).exists():
73
            raise forms.ValidationError("用户名已经存在!")
74
        return username
75

76
    # 在判断一个邮箱是否已存在之类的。。。代码与上面的一致
77

78
    def clean_re_password(self):
79
        password = self.cleaned_data.get("password", "")
80
        re_password = self.cleaned_data.get("re_password", "")
81
        if password != re_password:
82
            raise forms.ValidationError("两次输入的密码不一致")
83
            # 再往下走的话就是捕获错误异常
84
            # 添加异常给errors
85
        return re_password
 
 
后端代码
<wiz_code_mirror>
 
 
 
21
 
 
 
 
 
1
def register(request):
2
    if request.method == "POST":
3
        reg_form = RegForm(request.POST)
4
        if reg_form.is_valid():
5
            # 验证通过
6
            print(reg_form.cleaned_data)
7
            reg_form.cleaned_data.pop("re_password")
8
            mobile = reg_form.cleaned_data.get("mobile", None)
9
            username = reg_form.cleaned_data.get("username", None)
10
            password = reg_form.cleaned_data.get("password", None)
11
            avatar_img = request.FILES.get("head_logo", None)
12
            UserInfo.objects.create_user(username=username, avatar=avatar_img, phone=mobile, password=password)
13
            # 这个时候就要发送邮箱验证码提醒用户激活帐号!
14
            return HttpResponse('恭喜您注册成功!')
15
        # else:
16
            # 存在异常, 这里存在异常的话前端直接可以 reg_form.mobile.errors.0 取到,else下面的语句不用执行
17
    else:
18
        reg_form = RegForm()
19
    context = {}
20
    context['reg_form'] = reg_form
21
    return render(request, 'register.html', context)
 
 
完整的注册代码 前端

<wiz_code_mirror>
 
 
 
77
 
 
 
 
 
1
<!DOCTYPE html>
2
{% load staticfiles %}
3
<html lang="en">
4
<head>
5
    <meta charset="UTF-8">
6
    <title>Title</title>
7
    <link rel="stylesheet" href="{% static "bootstrap-3.3.7-dist/css/bootstrap.min.css" %}">
8
    <link rel="stylesheet" href="{% static 'my-style.css' %}">
9
    <script src="{% static 'jquery-1.12.4.min.js' %}"></script>
10
    <script src="{% static "bootstrap-3.3.7-dist/js/bootstrap.min.js" %}"></script>
11
    <style>
12
        .panel {
13
            margin-top: 50px;
14
        }
15
    </style>
16

17
</head>
18
<body>
19
<div class="container">
20
    <div class="row">
21
        <div class="col-xs-6 col-xs-offset-3">
22
            <!-- 表单 -->
23
            <div class="panel panel-default">
24
                <div class="panel-body">
25
                    <form class="form-horizontal" method="post" novalidate enctype="multipart/form-data">
26
                        {% csrf_token %}
27

28
                        <div class="form-group form">
29
                            <label for="{{ reg_form.username.id_for_label }}"
30
                                   class="col-sm-2 control-label">{{ reg_form.username.label }}</label>
31
                            <div class="col-sm-10">
32
                                {{ reg_form.username }}
33
                                <span class="has-error">{{ reg_form.username.errors.0 }}</span>
34
                            </div>
35
                        </div>
36
                        ...  ... ...
37
                        <div class="form-group form">
38
                            <label class="col-sm-2 control-label">头像</label>
39
                            <div class="col-sm-10">
40
                                <label for="avatar">
41
                                    <img src="/static/img/touxiang.jpg/" id="avatar-img">
42
                                </label>
43
                                <input type="file" id="avatar" style="display: none" name="head_logo">
44
                            </div>
45
                        </div>
46

47
                        <div class="form-group">
48
                            <div class="col-sm-12">
49
                                <input type="button" value="提交" class="btn btn-default pull-right" id="reg_btn">
50
                            </div>
51
                        </div>
52
                        
53
                    </form>
54
                </div>
55
            </div>
56
        </div>
57
    </div>
58
</div>
59

60
<script>
61
    // 头像预览功能实现
62
    $("#avatar").change(function () {
63
        // 1.创建一个文件读取对象
64
        var fileReader = new FileReader();
65
        // 取到当前选中的头像文件
66
        // console.log(this.files[0]);
67
        // 读取选到的对象
68
        fileReader.readAsDataURL(this.files[0]);
69
        // 2.等读取完文件之后在把图片加载到img标签中
70
        fileReader.onload = function () {
71
            $("#avatar-img").attr("src", fileReader.result);
72
        };
73
    });
74
</script>
75
    
76
</body>
77
</html>
 
 

        Ajax提交文件数据

Ajax提交带文件的数据也是有坑的
<wiz_code_mirror>
 
 
 
1
 
 
 
 
 
1
formDate.append("avatar", $("#avatar")[0].files[0]);    // 取input file文件里面的文件
 
 
后台接收到的是Ajax提交过来的数据,所以
<wiz_code_mirror>
 
 
 
1
 
 
 
 
 
1
avatar = request.FILES.get('avatar', None)      # 这里的avatar是Ajax提交过来的数据
 
 
 
视图函数
<wiz_code_mirror>
 
 
 
25
 
 
 
 
 
1
def register(request):
2
    if request.method == "POST":
3
        reg_form = RegForm(request.POST)
4
        ret = {'status': False, 'msg': ""}
5
        if reg_form.is_valid():
6
            # 取出清洗过的数据保存至数据库中
7
            username = reg_form.cleaned_data.get('username', '')
8
            # 这个密码需要加密
9
            password = reg_form.cleaned_data.get('password', '')
10
            mobile = reg_form.cleaned_data.get('mobile', '')
11
            avatar = request.FILES.get('avatar', None)      # 这里的avatar是Ajax提交过来的数据
12
            print(avatar)
13
            UserInfo.objects.create_user(username=username, password=password, phone=mobile, avatar=avatar)
14
            # 用户注册信息保存成功返回JsonResponce
15
            ret['status'] = True
16
            ret['msg'] = "/login/"
17
            return JsonResponse(ret)
18
        else:
19
            # 用户填写的字段有问题
20
            ret['msg'] = reg_form.errors
21
            return JsonResponse(ret)
22

23
    context = {}
24
    context['reg_form'] = RegForm()
25
    return render(request, 'register.html', context)
 
 
前端代码
<wiz_code_mirror>
 
 
 
x
 
 
 
 
 
1
<!DOCTYPE html>
2
{% load staticfiles %}
3
<html lang="en">
4
<head>
5
    <meta charset="UTF-8">
6
    <title>Title</title>
7
    <link rel="stylesheet" href="{% static "bootstrap-3.3.7-dist/css/bootstrap.min.css" %}">
8
    <link rel="stylesheet" href="{% static 'my-style.css' %}">
9
</head>
10
<body>
11
<div class="container">
12
    <div class="row">
13
        <div class="col-xs-6 col-xs-offset-3">
14
            <!-- 表单 -->
15
            <div class="panel panel-default">
16
                <div class="panel-body">
17
                    <form class="form-horizontal" method="post" novalidate enctype="multipart/form-data">
18
                        {% csrf_token %}
19

20
                        <div class="form-group form">
21
                            <label for="{{ reg_form.username.id_for_label }}"
22
                                   class="col-sm-2 control-label">{{ reg_form.username.label }}</label>
23
                            <div class="col-sm-10">
24
                                {{ reg_form.username }}
25
                                <span class="has-error">{{ reg_form.username.errors.0 }}</span>
26
                            </div>
27
                        </div>
28
                        ... ... ...
29
                        <div class="form-group form">
30
                            <label class="col-sm-2 control-label">头像</label>
31
                            <div class="col-sm-10">
32
                                <label for="avatar">
33
                                    <img src="/static/img/touxiang.jpg/" id="avatar-img">
34
                                </label>
35
                                <input type="file" id="avatar" style="display: none" name="head_logo">
36
                            </div>
37
                        </div>
38

39
                        <div class="form-group">
40
                            <div class="col-sm-12">
41
                                <input type="button" value="提交" class="btn btn-default pull-right" id="reg_btn">
42
                            </div>
43
                        </div>
44
                    </form>
45
                </div>
46
            </div>
47
        </div>
48
    </div>
49
</div>
50

51
<script src="{% static 'jquery-1.12.4.min.js' %}"></script>
52
<script src="{% static 'bootstrap-3.3.7-dist/js/bootstrap.min.js' %}"></script>
53

54
<script>
55
    // 上传的头像图片实时预览
56
    $("#avatar").change(function () {
57
        // 新建一个文件读取对象
58
        var fileReader = new FileReader();
59
        // 用FileReader里面的readAsDataURL()方法取到url路径
60
        fileReader.readAsDataURL(this.files[0]);
61
        fileReader.onload = function () {
62
            $("#avatar-img").attr("src", fileReader.result);
63
        }
64
    });
65

66
    //  Ajax提交数据给后台
67
    $("#reg_btn").click(function () {
68
        // 为提交按钮绑定点击事件,我们这次提交的是带图片的文件所以需特殊处理
69
        var formDate = new FormData();
70
        formDate.append("username", $("#id_username").val());
71
        formDate.append("password", $("#id_password").val());
72
        formDate.append("re_password", $("#id_re_password").val());
73
        formDate.append("mobile", $("#id_mobile").val());
74
        formDate.append("avatar", $("#avatar")[0].files[0]);    // 取input file文件里面的文件
75
        formDate.append("csrfmiddlewaretoken", $("[name='csrfmiddlewaretoken']").val());
76

77
        $.ajax({
78
            url: "/register/",
79
            type: 'POST',
80
            // 必须加上这两句
81
            processData: false,
82
            contentType: false,
83
            data: formDate,
84
            success: function (data) {
85
                console.log(data);
86
               // 如果成功了,就给我跳转至某个页面,
87
                if (data.status){
88
                    location.href = data.msg;
89
                }else{
90
                // 如果失败,找到具体的某个字段的错误值就将失败的信息展示出来
91
                    $.each(data.msg, function (k, v) {
92
                        // k是键,v是错误的值
93
                        $("#id_" + k).next("span").text(v[0]).parent().parent().addClass("has-error")
94
                    })
95
                }
96
            }
97
        });
98
    });
99

100
</script>
101
</body>
102
</html>
103

104

 
 
提交成功的话会自动生成文件,将提交的文件放入其中

        补充知识点        

        JS中的FormData对象    


     jQuery中的for循环    

     加载文件的两种写法
 
 
 

用户注册的邮箱验证与激活

 
 
 
 
 
 
 
 
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!