美多商城之用户注册(用户注册业务实现)

三、用户注册业务实现

3.1用户注册业务逻辑分析

1. 用户注册业务逻辑分析

3.2 用户注册接口设计和定义

1. 设计接口基本思路

  • 对于接口的设计,我们要根据具体的业务逻辑,设计出适合业务逻辑的接口。
  • 设计接口的思路:
    • 分析要实现的业务逻辑:
      • 明确在这个业务中涉及到几个相关子业务。
      • 将每个子业务当做一个接口来设计。
    • 分析接口的功能任务,明确接口的访问方式与返回数据:
      • 请求方法(如GET、POST、PUT、DELETE等)。
      • 请求地址。
      • 请求参数(如路径参数、查询字符串、表单、JSON等)。
      • 响应数据(如HTML、JSON等)。

2. 用户注册接口设计

1.请求方式

选项方案
请求方法POST
请求地址/register/

2.请求参数:表单参数

参数名类型是否必传说明
usernamestring用户名
passwordstring密码
password2string确认密码
mobilestring手机号
sms_codestring短信验证码
allowstring是否同意用户协议

3.响应结果:HTML

  • register.html
响应结果响应内容
注册失败响应错误提示
注册成功重定向到首页

3. 用户注册接口定义

1.注册视图

view.py

class RegisterView(View):
    """用户注册"""

    def get(self, request):
        """
        提供注册界面
        :param request: 请求对象
        :return: 注册界面
        """
        return render(request, 'register.html')

    def post(self, request):
        """
        实现用户注册
        :param request: 请求对象
        :return: 注册结果
        """
        pass

2.总路由

urlpatterns = [
    # users
    url(r'^', include('users.urls', namespace='users')),
]

3.子路由

from django.conf.urls import url
from . import views

urlpatterns = [
    #  注册
    url(r'^register/$', views.RegisterView.as_view(), name='register'),
]

3.3 用户注册前端逻辑

为了学会使用Vue.js的双向绑定实现用户的交互和页面局部刷新效果。

1. 用户注册页面绑定Vue数据

1.准备div盒子标签

<div id="app">
    <body>
    ......
    </body>
</div>

2.register.html

  • 绑定内容:变量、事件、错误提示等
<form method="post" class="register_form" @submit="on_submit" v-cloak>
    {{ csrf_input }}
    <ul>
        <li>
            <label>用户名:</label>
            <input type="text" v-model="username" @blur="check_username" name="username" id="user_name">
            <span class="error_tip" v-show="error_name">[[ error_name_message ]]</span>
        </li>
        <li>
            <label>密码:</label>
            <input type="password" v-model="password" @blur="check_password" name="password" id="pwd">
            <span class="error_tip" v-show="error_password">请输入8-20位的密码</span>
        </li>
        <li>
            <label>确认密码:</label>
            <input type="password" v-model="password2" @blur="check_password2" name="password2" id="cpwd">
            <span class="error_tip" v-show="error_password2">两次输入的密码不一致</span>
        </li>
        <li>
            <label>手机号:</label>
            <input type="text" v-model="mobile" @blur="check_mobile" name="mobile" id="phone">
            <span class="error_tip" v-show="error_mobile">[[ error_mobile_message ]]</span>
        </li>
        <li>
            <label>图形验证码:</label>
            <input type="text" name="image_code" id="pic_code" class="msg_input">
            <img src="{{ static('images/pic_code.jpg') }}" alt="图形验证码" class="pic_code">
            <span class="error_tip">请填写图形验证码</span>
        </li>
        <li>
            <label>短信验证码:</label>
            <input type="text" name="sms_code" id="msg_code" class="msg_input">
            <a href="javascript:;" class="get_msg_code">获取短信验证码</a>
            <span class="error_tip">请填写短信验证码</span>
        </li>
        <li class="agreement">
            <input type="checkbox" v-model="allow" @change="check_allow" name="allow" id="allow">
            <label>同意”美多商城用户使用协议“</label>
            <span class="error_tip2" v-show="error_allow">请勾选用户协议</span>
        </li>
        <li class="reg_sub">
            <input type="submit" value="注 册">
        </li>
    </ul>
</form>

2. 用户注册JS文件实现用户交互

1.导入Vue.js库和ajax请求的库

<script type="text/javascript" src="{{ static('js/vue-2.5.16.js') }}"></script>
<script type="text/javascript" src="{{ static('js/axios-0.18.0.min.js') }}"></script>

2.准备register.js文件

<script type="text/javascript" src="{{ static('js/register.js') }}"></script>

绑定内容:变量、事件、错误提示等

let vm = new Vue({
	el: '#app',
	// 修改Vue读取变量的语法
    delimiters: ['[[', ']]'],
	data: {
		username: '',		// 用户名
		password: '', 		// 密码
		password2: '',		// 确认密码
		mobile: '',			// 手机号
		allow: '',			// 同意协议

		error_name: false,
		error_password: false,
		error_password2: false,
		error_mobile: false,
		error_allow: false,

		error_name_message: '',		// 用户名错误提示
		error_mobile_message: '',	// 密码错误提示
	},
	methods: {
		// 校验用户名
		check_username(){
			// 准备正则表达式
			let re = /^[a-zA-Z0-9_-]{5,20}$/;
			// 正则表达式匹配用户名
			if (re.test(this.username)) {
				this.error_name = false;
			} else {
				this.error_name_message = '请输入5-20个字符的用户名';
				this.error_name = true;
			}
		},
		// 校验密码
		check_password(){
			let re = /^[0-9A-Za-z]{8,20}$/;
			if (re.test(this.password)) {
				this.error_password = false;
			} else {
				this.error_password = true;
			}
		},
		// 校验确认密码
		check_password2(){
			// 判断两次密码是否一致
			if(this.password != this.password2) {
				this.error_password2 = true;
			} else {
				this.error_password2 = false;
			}
		},
		// 校验手机号
		check_mobile(){
			let re = /^1[3-9]\d{9}$/;
			if(re.test(this.mobile)) {
				this.error_mobile = false;
			} else {
				this.error_mobile_message = '您输入的手机号格式不正确';
				this.error_mobile = true;
			}
		},
		// 校验是否勾选协议
		check_allow(){
			if(!this.allow) {
				this.error_allow = true;
			} else {
				this.error_allow = false;
			}
		},
		// 监听表单提交事件
		on_submit(){
			this.check_username();
			this.check_password();
			this.check_password2();
			this.check_mobile();
			this.check_allow();

			if(this.error_name == true || this.error_password == true || this.error_password2 == true
				|| this.error_mobile == true || this.error_allow == true) {
                // 禁用表单的提交
				window.event.returnValue = false;
            }
		},
	}
});

3.用户交互事件实现

methods: {
    // 校验用户名
    check_username(){
        let re = /^[a-zA-Z0-9_-]{5,20}$/;
        if (re.test(this.username)) {
            this.error_name = false;
        } else {
            this.error_name_message = '请输入5-20个字符的用户名';
            this.error_name = true;
        }
    },
    // 校验密码
    check_password(){
        let re = /^[0-9A-Za-z]{8,20}$/;
        if (re.test(this.password)) {
            this.error_password = false;
        } else {
            this.error_password = true;
        }
    },
    // 校验确认密码
    check_password2(){
        if(this.password != this.password2) {
            this.error_password2 = true;
        } else {
            this.error_password2 = false;
        }
    },
    // 校验手机号
    check_mobile(){
        let re = /^1[3-9]\d{9}$/;
        if(re.test(this.mobile)) {
            this.error_mobile = false;
        } else {
            this.error_mobile_message = '您输入的手机号格式不正确';
            this.error_mobile = true;
        }
    },
    // 校验是否勾选协议
    check_allow(){
        if(!this.allow) {
            this.error_allow = true;
        } else {
            this.error_allow = false;
        }
    },
    // 监听表单提交事件
    on_submit(){
        this.check_username();
        this.check_password();
        this.check_password2();
        this.check_mobile();
        this.check_allow();

        if(this.error_name == true || this.error_password == true || this.error_password2 == true
            || this.error_mobile == true || this.error_allow == true) {
            // 禁用表单的提交
            window.event.returnValue = false;
        }
    },
}

4. 知识要点

  1. Vue绑定页面的套路
    • 导入Vue.js库和ajax请求的库
    • 准备div盒子标签
    • 准备js文件
    • html页面绑定变量、事件等
    • js文件定义变量、事件等
  2. 错误提示
    • 如果错误提示信息是固定的,可以把错误提示信息写死,再通过v-show控制是否展示
    • 如果错误提示信息不是固定的,可以使用绑定的变量动态的展示错误提示信息,再通过v-show控制是否展示
  3. 修改Vue变量的读取语法,避免和Django模板语法冲突
    • delimiters: ['[[', ']]']
  4. 后续的页面中如果有类似的交互和刷新效果,也可按照此套路实现

3.4 用户注册后端逻辑

1. 接收参数

提示:用户注册数据是从注册表单发送过来的,所以使用request.POST来提取。

username = request.POST.get('username')
password = request.POST.get('password')
password2 = request.POST.get('password2')
mobile = request.POST.get('mobile')
allow = request.POST.get('allow')

2. 校验参数

前端校验过的后端也要校验,后端的校验和前端的校验是一致的

【前后端的校验是分开的,避免恶意用户超过前端逻辑发出请求,要保证后端的安全,前后端的校验逻辑相同】

# 判断参数是否齐全
# 判断用户名是否是5-20个字符
# 判断密码是否是8-20个数字
# 判断两次密码是否一致
# 判断手机号是否合法
# 判断是否勾选用户协议
# 判断参数是否齐全
if not all([username, password, password2, mobile, allow]):
    return http.HttpResponseForbidden('缺少必传参数')
# 判断用户名是否是5-20个字符
if not re.match(r'^[a-zA-Z0-9_-]{5,20}$', username):
    return http.HttpResponseForbidden('请输入5-20个字符的用户名')
# 判断密码是否是8-20个数字
if not re.match(r'^[0-9A-Za-z]{8,20}$', password):
    return http.HttpResponseForbidden('请输入8-20位的密码')
# 判断两次密码是否一致
if password != password2:
    return http.HttpResponseForbidden('两次输入的密码不一致')
# 判断手机号是否合法
if not re.match(r'^1[3-9]\d{9}$', mobile):
    return http.HttpResponseForbidden('请输入正确的手机号码')
# 判断是否勾选用户协议
if allow != 'on':
    return http.HttpResponseForbidden('请勾选用户协议')

提示:这里校验的参数,前端已经校验过,如果此时参数还是出错,说明该请求是非正常渠道发送的,所以直接禁止本次请求。

3. 保存注册数据   【是注册业务的核心】

  • 这里使用Django认证系统用户模型类提供的 create_user() 方法创建新的用户。
  • 这里 create_user() 方法中封装了 set_password() 方法加密密码。
# 保存注册数据
try:
    User.objects.create_user(username=username, password=password, mobile=mobile)
except DatabaseError:
    return render(request, 'register.html', {'register_errmsg': '注册失败'})

# 响应注册结果
return http.HttpResponse('注册成功,重定向到首页')

如果注册失败,我们需要在页面上渲染出注册失败的提示信息。

在register.html中进行修改:

{% if register_errmsg %}
    <span class="error_tip2">{{ register_errmsg }}</span>
{% endif %}

4. 响应注册结果

  • 重要提示:注册成功,重定向到首页

1.创建首页广告应用:contents

$ cd ~/projects/meiduo_project/meiduo_mall/meiduo_mall/apps
$ python ../../manage.py startapp contents

2.定义首页广告视图:IndexView

from django.shortcuts import render
from django.views import View


# Create your views here.


class IndexView(View):
    """首页广告"""

    def get(self, request):
        """提供首页广告界面"""
        return render(request, 'index.html')

3.配置首页广告路由:绑定命名空间

# contents
url(r'^', include('contents.urls', namespace='contents')),
from django.conf.urls import url
from . import views


urlpatterns = [
    #  首页广告
    url(r'^$', views.IndexView.as_view(), name='index')
]

4.测试首页广告是否可以正常访问

http://127.0.0.1:8000/

5.响应注册结果:重定向到首页

# 响应注册结果
return redirect(reverse('contents:index'))

5. 知识要点

  1. 后端逻辑编写套路:
    • 业务逻辑分析
    • 接口设计和定义
    • 接收和校验参数
    • 实现主体业务逻辑
    • 响应结果
  2. 注册业务逻辑核心思想:
    • 保存用户注册数据

3.5 状态保持

说明:

  • 如果需求是注册成功后即表示用户登入成功,那么此时可以在注册成功后实现状态保持
  • 如果需求是注册成功后不表示用户登入成功,那么此时不用在注册成功后实现状态保持

美多商城的需求是:注册成功后即表示用户登入成功

1. login()方法介绍

  1. 用户登入本质:
    • 状态保持
    • 将通过认证的用户的唯一标识信息(比如:用户ID)写入到当前浏览器的 cookie 和服务端的 session 中。
  2. login()方法:
    • Django用户认证系统提供了login()方法。
    • 封装了写入session的操作,帮助我们快速登入一个用户,并实现状态保持。
  3. login()位置:

    • django.contrib.auth.__init__.py文件中。

      login(request, user, backend=None)
      
  4. 状态保持 session 数据存储的位置:Redis数据库的1号库
     SESSION_ENGINE = "django.contrib.sessions.backends.cache"
     SESSION_CACHE_ALIAS = "session"
    

2. login()方法登入用户

# 保存注册数据
try:
    user = User.objects.create_user(username=username, password=password, mobile=mobile)
except DatabaseError:
    return render(request, 'register.html', {'register_errmsg': '注册失败'})

# 登入用户,实现状态保持
login(request, user)

# 响应注册结果
return redirect(reverse('contents:index'))

3. 查看状态保持结果

4. 知识要点

  1. 登入用户,并实现状态保持的方式:login(request, user, backend=None)

3.6 用户名重复注册

1. 用户名重复注册逻辑分析

2. 用户名重复注册接口设计和定义

1.请求方式

选项方案
请求方法GET
请求地址/usernames/(?P[a-zA-Z0-9_-]{5,20})/count/

2.请求参数:路径参数

参数名类型是否必传说明
usernamestring用户名

3.响应结果:JSON

响应结果响应内容
code状态码
errmsg错误信息
count记录该用户名的个数

3. 用户名重复注册后端逻辑

class UsernameCountView(View):
    """判断用户名是否重复注册"""

    def get(self, request, username):
        """
        :param request: 请求对象
        :param username: 用户名
        :return: JSON
        """
        count = User.objects.filter(username=username).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})

4. 用户名重复注册前端逻辑

if (this.error_name == false) {
    let url = '/usernames/' + this.username + '/count/';
    axios.get(url,{
        responseType: 'json'
    })
        .then(response => {
            if (response.data.count == 1) {
                this.error_name_message = '用户名已存在';
                this.error_name = true;
            } else {
                this.error_name = false;
            }
        })
        .catch(error => {
            console.log(error.response);
        })
}

5. 知识要点

  1. 判断用户名重复注册的核心思想:
    • 使用用户名查询该用户名对应的记录是否存在,如果存在,表示重复注册了,反之,没有重复注册。
  2. axios发送异步请求套路:
    • 处理用户交互
    • 收集请求参数
    • 准备请求地址
    • 发送异步请求
    • 得到服务器响应
    • 控制界面展示效果

3.7 手机号重复注册

1. 手机号重复注册逻辑分析

2. 手机号重复注册接口设计和定义

1.请求方式

选项方案
请求方法GET
请求地址/mobiles/(?P1[3-9]\d{9})/count/

2.请求参数:路径参数

参数名类型是否必传说明
mobilestring手机号

3.响应结果:JSON

响应结果响应内容
code状态码
errmsg错误信息
count记录该用户名的个数

3. 手机号重复注册后端逻辑

class MobileCountView(View):
    """判断手机号是否重复注册"""

    def get(self, request, mobile):
        """
        :param request: 请求对象
        :param mobile: 手机号
        :return: JSON
        """
        count = User.objects.filter(mobile=mobile).count()
        return http.JsonResponse({'code': RETCODE.OK, 'errmsg': 'OK', 'count': count})

4. 手机号重复注册前端逻辑

if (this.error_mobile == false) {
    let url = '/mobiles/'+ this.mobile + '/count/';
    axios.get(url, {
        responseType: 'json'
    })
        .then(response => {
            if (response.data.count == 1) {
                this.error_mobile_message = '手机号已存在';
                this.error_mobile = true;
            } else {
                this.error_mobile = false;
            }
        })
        .catch(error => {
            console.log(error.response);
        })
}
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值