BBS-注册功能

重点功能:

  1. 上传图片
  2. 头像图片实时展示
  3. ajax方式提交给后端数据

一、添加路由

在路由urls.py中要先导入视图层和一些用到的模块

from django.conf.urls import url
from django.contrib import admin
from app01 import views

然后添加

# 注册的路由,用精准匹配
url(r'^register/$', views.register),

路由问题:如果没有参数尽量使用精准匹配,防止路由冲突

二、注册功能前端模板

前端步骤:

1.form表单展示数据框:用户名、密码、二次密码、邮箱、头像、button按钮
# button按钮,使用ajax提交数据,就不能使用submit了
2.头像图片格式
    2.1 先设置默认头像,放到静态文件中,记得配置文件设置
    2.2  img标签中加路径,并调整大小
    	<img src="/static/img/default.png" id="myimg" alt="" width="100px">
    # 前端检查中可以先临时调整尺寸
    2.3 点击图片就可以上传文件:把img标签放到label中,把file的input框隐藏掉
3.头像图片实时展示  # 用js
    3.1 给myfile帮点change事件
    3.2 自定义文件阅读器对象
    3.3 获取新的图片真实数据
    3.4 把文件数据交给文件阅读器
    	myFileReadObj.readAsDataURL(myfile); 
    3.5 给文件阅读器绑定onload事件
    3.6 更改img标签的路径属性
    	$("#myimg").attr('src', myFileReadObj.result);
4.ajax方式提交给后端数据
    4.1 获取前端form表单中输入的数据
    4.2 参数的验证,参数不能为空、两次密码不一致
    4.3 formdata对象,添加普通数据、文件数据、csrf验证
    4.4 发起ajax请求:把前端输入的数据提交到后端
    4.5 接收后端的返回信息,back_dic字典


# 记住:以后但凡遇到参数的时候,都需要验证!!!!!!!!
# 前端的验证是弱不禁风的,Django的后端一定要做验证,参数必填,参数不正确,参数不合法
'''作为一个后端开发人员,如果不验证参数,不是一个合格的后端开发人员'''

补充:前端检查图片的大小,只能用于临时调整
精细调整:点中自己改的尺寸,键盘上下键,就可以增删数据。优点:更方便

前端代码

layui网址:https://layui.gitee.io/v2/docs/modules/layer.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>注册页面</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.4/jquery.min.js"></script>
    <script src="https://stackpath.bootstrapcdn.com/bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <h1 class="text-center">注册页面</h1>
            <form action="">
                <div class="form-group">
                    {# label标签的作用:当点击用户名时,也能够让输入框获取焦点 -->#}
                    {# label标签的 for 属性值应当与相关元素的 id 属性值相同。 -->#}
                    <label for="username">用户名:</label>
                    <input type="text" id="username" class="form-control">
                </div>
                <div class="form-group">
                    <label for="password">密码:</label>
                    <input type="password" id="password" class="form-control">
                </div>
                <div class="form-group">
                    <label for="re_password">确认密码:</label>
                    <input type="password" id="re_password" class="form-control">
                </div>
                <div class="form-group">
                    <label for="email">邮箱:</label>
                    <input type="text" id="email" class="form-control">
                </div>
                <div class="form-group">
                    <label for="myfile">上传头像:
                        <img src="/static/img/default.png" id="myimg" alt="" width="90px">
                        {# 图片路径写默认图片的静态路径,图片要调整大小 #}
                    </label> {# 点击图片就可以上传文件,就要把img标签放到label中 #}
                    <input type="file" id="myfile" style="display: none"> {# 隐藏file的input框 #}
                </div>
                {# 使用ajax提交给后端数据,所以type使用button #}
                <input type="button" class="btn btn-primary btn-block commit" value="提交">
            </form>
        </div>
    </div>
</div>

{# 引入layer文件 #}
<script src="/static/layer/layer.js"></script>

<script>
    // 使用js来实时显示图片
    $("#myfile").change(function () {  {# 换张图片,文本域就会发生变化,所以绑定change事件 #}
        // 1. 借助于文件阅读器
        var myFileReadObj = new FileReader();  // 文件阅读器:可以读取文件

        // 2. 获取新文件/图片数据
        // var myfile = $("#myfile")[0].files[0];
        var myfile = $(this)[0].files[0];
        {# 事件函数中的this关键字,指代的就是当前被操作的标签对象本身 #}

        // 3. 把你拿到的这个文件交给文件阅读器
        myFileReadObj.readAsDataURL(myfile);  // 这一步是异步提交

        // 4.返回一个图片的数据
        // 怎么显示新图片?就是把新图片的地址替换到默认图片的地址src=""中

        myFileReadObj.onload = function () {  {# 把图片读取完成后再执行更改属性操作:onload事件 #}
            // 读出文件对象的图片地址
            $("#myimg").attr('src', myFileReadObj.result);
            {# 更改属性操作:attr、prop #}
        }
    });

    // ajax方式提交给后端数据
    $(".commit").click(function () {
        // 1.获取前端form表单中输入的数据
        var username = $("#username").val();
        var password = $("#password").val();
        var re_password = $("#re_password").val();
        var email = $("#email").val();
        var myfile = $("#myfile")[0].files[0];

        // 2.参数的验证
        if (!username) {
            layer.msg('用户名必填!');  // 如果用户名没有填写,弹窗提示
            return
            {# 参数不正确直接退出 #}
        }
        if (!password) {
            layer.msg('密码必须填写!')
            return
        }
        if (!re_password) {
            layer.msg('确认密码必须填写!')
            return
        }
        if (!email) {
            layer.msg('邮箱必须填写!')
            return
        }
        // 其余参数你自己来验证,多个参数验证:方式1:可以写多个if条件。方式2:可以直接循环$.each()
        // 两次密码不一致
		if(password != re_password){
            layer.msg('两次密码不一致');
            return;
        }
            
        // 3.formdata对象
        // 文件数据传输需要借助于formdata对象
        var myFormDataObj = new FormData();
        // 普通数据
        myFormDataObj.append('username', username);
        myFormDataObj.append('password', password);
        myFormDataObj.append('re_password', re_password);
        myFormDataObj.append('email', email);
        // 文件数据
        myFormDataObj.append('myfile', myfile);
        //csrf_token验证
        myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');

        // 4.发起ajax请求:把前端输入的数据提交到后端
        $.ajax({
            url: '',
            type: 'post',
            data: myFormDataObj,
            contentType: false, {# 使用myFormDataObj对象,需要加两个参数 #}
            processData: false,

            success: function (res) {  // res=back_dic
                if (res.code == 200) {
                    layer.msg(res.msg, {icon: 1}, function () {
                        location.href = res.url;  // 跳转地址,前端BOM操作
                    });
                } else {  // 不成功的其余都只layer弹出各自的消息
                    layer.msg(res.msg);
                }
            }
        })
    })
</script>
</body>
</html>

前端重点操作

1、注册功能图片实时展示

步骤:

3.头像图片实时展示  # 用js
    3.1 给myfile帮点change事件
    3.2 自定义文件阅读器对象
    3.3 获取新的图片真实数据
    3.4 把文件数据交给文件阅读器
    	myFileReadObj.readAsDataURL(myfile); 
    3.5 给文件阅读器绑定onload事件
    3.6 更改img标签的路径属性
    	$("#myimg").attr('src', myFileReadObj.result);

代码:

    // 使用js来实时显示图片
    {# 换张图片,文本域就会发生变化,所以绑定change事件 #}
    $("#myfile").change(function () {
        // 1. 借助于文件阅读器
        var myFileReadObj = new FileReader();  // 文件阅读器:可以读取文件

        // 2. 获取新文件/图片数据
        {# var myfile = $("#myfile")[0].files[0]; #}
        {# 事件函数中的this关键字,指代的就是当前被操作的标签对象本身 #}
        var myfile = $(this)[0].files[0];

        // 3. 把你拿到的这个文件交给文件阅读器
        myFileReadObj.readAsDataURL(myfile);  // 这一步是异步提交

        // 4.返回一个图片的数据
        {# 怎么显示新图片?就是把新图片的地址替换到默认图片的地址src=""中 #}

        {# 把图片读取完成后再执行更改属性操作:onload事件 #}
        myFileReadObj.onload = function () {
            {# 更改属性操作:attr、prop #}
            $("#myimg").attr('src', myFileReadObj.result);  {# 读出文件对象的图片地址 #}
        }
    });

注意点:

  1. 前端的图片并没有上传成功,没有上传到后台
  2. base64的图片的真实数据,二进制形式

图片实时展示的第二种思路:
(可以自己写一下)
ajax提交文件数据,把图片上传到后台,django返回给前端一个json格式数据,内部带一个图片地址/路径,属性更改:

$("#myimg").attr('src', '后端传给前端的图片路径数据');

2、注册功能ajax提交数据

前端ajax方式提交给后端数据的逻辑步骤:
4.1 获取前端form表单中输入的数据
4.2 参数的验证,参数不能为空、两次密码不一致
4.3 formdata对象,添加普通数据、文件数据、csrf验证
4.4 发起ajax请求:把前端输入的数据提交到后端
4.5 接收后端的返回信息,back_dic字典

代码:

    // ajax方式提交给后端数据
    $(".commit").click(function () {
        // 1.获取前端form表单中输入的数据
        var username = $("#username").val();
        var password = $("#password").val();
        var re_password = $("#re_password").val();
        var email = $("#email").val();
        var myfile = $("#myfile")[0].files[0];

        // 2.参数的验证
        if (!username) {
            layer.msg('用户名必填!');  // 如果用户名没有填写,弹窗提示
            return
            {# 参数不正确直接退出 #}
        }
        if (!password) {
            layer.msg('密码必须填写!')
            return
        }
        if (!re_password) {
            layer.msg('确认密码必须填写!')
            return
        }
        if (!email) {
            layer.msg('邮箱必须填写!')
            return
        }
        // 其余参数你自己来验证,多个参数验证:方式1:可以写多个if条件。方式2:可以直接循环$.each()
        // 两次密码不一致
		if(password != re_password){
            layer.msg('两次密码不一致');
            return;
        }
            
        // 3.formdata对象
        // 文件数据传输需要借助于formdata对象
        var myFormDataObj = new FormData();
        // 普通数据
        myFormDataObj.append('username', username);
        myFormDataObj.append('password', password);
        myFormDataObj.append('re_password', re_password);
        myFormDataObj.append('email', email);
        // 文件数据
        myFormDataObj.append('myfile', myfile);
        //csrf_token验证
        myFormDataObj.append('csrfmiddlewaretoken', '{{ csrf_token }}');

        // 4.发起ajax请求:把前端输入的数据提交到后端
        $.ajax({
            url: '',
            type: 'post',
            data: myFormDataObj,
            contentType: false, {# 使用myFormDataObj对象,需要加两个参数 #}
            processData: false,

            success: function (res) {  // res=back_dic
                if (res.code == 200) {
                    layer.msg(res.msg, {icon: 1}, function () {
                        location.href = res.url;  // 跳转地址,前端BOM操作
                    });
                } else {  // 不成功的其余都只layer弹出各自的消息
                    layer.msg(res.msg);
                }
            }
        })
    })

知识点:

location.href="URL" // 跳转到指定页面,前端BOM操作

BOM操作复习:https://www.cnblogs.com/zjyao/p/17335370.html#location对象务必掌握

拓展:
1.前端的参数验证:
如果有多个参数需要验证,可以使用$.each()方法,把每个输入框的id值拿到,并给每一个框加个msg属性(eg: msg="请输入用户名"),循环id,获取msg属性值。也可以直接简单的使用多个if判断条件即可
2.密码加密的问题
md5加密的位数是32位数,有的公司不会显示这么长,只显示16位,会先加密,然后切片截取,只显示16位。

三、添加视图函数

后端步骤

标准的后端逻辑:

1. 先定义返回给前端的数据格式
2. 接收参数
3. 验证参数!
4. 开始处理正常的业务逻辑
5. 返回前端数据:back_dic

注册功能中的业务逻辑:

4. 开始处理正常的业务逻辑  # 注册功能
    4.1 密码加密
    4.2 把数据添加到字典中,文件数据可传也可不传,需要判断
    4.3 数据保存到数据库中
"""能在后端处理的就在后端处理"""

拓展:
业务状态码code:

是我们程序员自己写的,可以随意定义。
200:成功
一般是4为数字(eg:1001:用户名没有填写)
还可能出现6位(eg:421001,表示跟OA相关的(财务41 OA42 后台43 )),前两位表示业务模块,后4为表示响应状态码
还可能:0,代表成功。1,代表失败

后端代码

在views.py中,

1、导入要用到的模块

from django.shortcuts import render, HttpResponse
from django.http import JsonResponse  # ajax请求,后端返回json格式数据,引入JsonResponse
from django.conf import settings  # 使用配置文件中的盐
from app01 import models  # 入库操作,要导入model.py文件
import hashlib  # 加密模块

2、加密函数

def get_md5_pwd(password):
    """加密函数"""
    m = hashlib.md5()
    s = password + settings.SECRET_KEY
    m.update(s.encode('utf-8'))
    return m.hexdigest()

3、然后添加视图函数 register

def register(request):
    '''注册功能'''
    # print(request.is_ajax())  # 判断是不是ajax提交
    # ajax的请求方式有get,post,不适合现在使用

    if request.method == 'POST':
        '''由于现在我们用的是ajax发起的请求,所以,我们后端一般返回json格式的数据,轻量级数据格式,速度快,优点多'''
        # 1. 先定义返回给前端的数据格式
        # code:叫业务状态码   200   1001  1002  1003----------> 财务411001  oa4210001  后台431001  订单 4410001
        # back_dic = {'code': 200, 'msg': '注册成功', 'data': []}  # 标准的返回给前端的数据格式
        back_dic = {'code': 200, 'msg': '注册成功'}

        # 2. 接收参数
        username = request.POST.get('username')
        password = request.POST.get('password')
        re_password = request.POST.get('re_password')
        email = request.POST.get('email')
        myfile = request.FILES.get('myfile')  # 文件数据用FILES接收

        # 3. 验证参数!!!!!!!, 作为后端开发人员,必须验证参数,验证的是合法的参数
        # 验证参数的时候,一定先验证错误的参数,不合法的参数,按照反向逻辑写
        if not username:
            back_dic['code'] = 1001
            back_dic['msg'] = '用户名必须填写'
            return JsonResponse(back_dic)
        if not password:
            back_dic['code'] = 1002
            back_dic['msg'] = '密码必须填写'
            return JsonResponse(back_dic)
        if not re_password:
            back_dic['code'] = 1003
            back_dic['msg'] = '确认密码必须填写'
            return JsonResponse(back_dic)
        if not email:
            back_dic['code'] = 1004
            back_dic['msg'] = '邮箱必须填写'
            return JsonResponse(back_dic)

        # 验证两次密码不一致
        if password != re_password:
            back_dic['code'] = 1005
            back_dic['msg'] = '两次密码不一致'
            return JsonResponse(back_dic)

        # 4. 开始处理正常的业务逻辑
        '''你完全可以使用auth模块,但是这里我不给你用auth模块,因为太简单了,扩展性不好。可以自己尝试一下使用auth模块'''
        # 4.1 密码加密
        new_pwd = get_md5_pwd(password)

        # 4.2 把数据添加到字典中
        data_dic = {}  # 字段比较多的时候,直接创建关键字传参的字典
        data_dic['username'] = username
        data_dic['password'] = new_pwd
        data_dic['email'] = email
        # 文件数据可传也可不传
        if myfile:
            data_dic['avatar'] = myfile  # 保存的是图片路径到avatar中

        # 4.3 数据保存到数据库中
        # models.UserInfo.objects.create(username=username, password=new_pwd, email=email, avatar=myfile)
        models.UserInfo.objects.create(**data_dic)

        # 5. 返回前端数据
        back_dic['url'] = '/login/'  # 注册成功后跳转到登录页面
        return JsonResponse(back_dic)
    return render(request, 'register.html')

posted @ 2023-05-14 16:25  星空看海  阅读(52)  评论(0编辑  收藏  举报