【美多商城项目 02】用户注册

一、用户模型类

1.1 定义用户模型类

1. Django默认用户认证系统

  • Django自带用户认证系统
    • 它处理用户账号、组、权限以及基于cookie的用户会话。
  • Django认证系统位置
    • django.contrib.auth包含认证框架的核心和默认的模型。
    • django.contrib.contenttypes是Django内容类型系统,它允许权限与你创建的模型关联。
  • Django认证系统同时处理认证和授权
    • 认证:验证一个用户是否它声称的那个人,可用于账号登录。
    • 授权:授权决定一个通过了认证的用户被允许做什么。
  • Django认证系统包含的内容
    • 用户:用户模型类、用户认证。
    • 权限:标识一个用户是否可以做一个特定的任务,MIS系统常用到。
    • 组:对多个具有相同权限的用户进行统一管理,MIS系统常用到。
    • 密码:一个可配置的密码哈希系统,设置密码、密码校验。

2. Django默认用户模型类

  • Django认证系统中提供了用户模型类User保存用户的数据。
    • User对象是认证系统的核心。
  • Django认证系统用户模型类位置

    • django.contrib.auth.models.User

  • 父类AbstractUser介绍

    • User对象基本属性
      • 创建用户必选:username、password
      • 创建用户可选:email、first_name、last_name、last_login、date_joined、is_active 、is_staff、is_superuse
      • 判断用户是否通过认证:is_authenticated
    • 创建用户的方法

      user = User.objects.create_user(username, email, password, **extra_fields)
      
    • 用户认证的方法

      from django.contrib.auth import authenticate
      user = authenticate(username=username, password=password, **kwargs)
      
    • 处理密码的方法

      • 设置密码:set_password(raw_password)
      • 校验密码:check_password(raw_password)

3. 自定义用户模型类

思考:为什么要自定义用户模型类?

  • 观察注册界面会发现,美多商城注册数据必选用户mobile信息
  • 但是Django默认用户模型类中没有mobile字段,所以要自定义用户模型类。

如何自定义用户模型类?

  • 继承自AbstractUser(可通过阅读Django默认用户模型类的源码得知) 。
  • 新增mobile字段。
from django.db import models
from django.contrib.auth.models import AbstractUser

# Create your models here.


class User(AbstractUser):
    """自定义用户模型类"""
    mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')

    class Meta:
        db_table = 'tb_users'
        verbose_name = '用户'
        verbose_name_plural = verbose_name

    def __str__(self):
        return self.username

4. 知识要点

  1. Django自带用户认证系统核心就是User对象
  2. Django用户认证系统包含了一系列对用户的操作,比如:模型类,认证,权限,分组,密码处理等。
  3. Django用户认证系统中的用户模型类可以自定义,继承自AbstractUser
  4. Django用户认证系统说明文档

1.2 迁移用户模型类

1. 指定用户模型类

文档

思考:为什么Django默认用户模型类是User?

  • 阅读源代码:'django.conf.global_settings’
    AUTH_USER_MODEL = 'auth.User'
    

结论:

  • Django用户模型类是通过全局配置项AUTH_USER_MODEL决定的

配置规则:

AUTH_USER_MODEL = '应用名.模型类名'
# 指定本项目用户模型类
AUTH_USER_MODEL = 'users.User'

2. 迁移用户模型类

1.创建迁移文件

  • python manage.py makemigrations

 

2.执行迁移文件

  • python manage.py migrate

 

3. 知识要点

  1. 用户认证系统中的用户模型类,是通过全局配置项AUTH_USER_MODEL决定的。
  2. 如果迁移自定义用户模型类,必须先配置 AUTH_USER_MODEL

二、用户注册业务实现

2.1 RESTful 设计方法( 入门 )

为什么需要使用 RESTful

在前后端分离的应用模式里,后端 API 接口如何定义?

例如

行业中以前的定义方式:

1 增加商品

# 增加商品
POST  /add-goods/

前端发送了 post 请求

请求路径为: /add-goods/

2 删除商品

# 删除商品
POST  /delete-goods/

前端又发送了 post 请求

请求路径为: /delete-goods/

3 修改商品

# 修改商品
POST /update-goods/ 修改商品

前端还是发送的 post 请求

请求路径为: /update-goods/

4 查询商品

# 查询商品
GET /get-goods/ 查询商品

前端发送的 get 请求

请求路径为: /get-goods/

总结:

对于接口的请求方式与路径,每个后端开发人员可能都有自己的定义方式,风格迥异。

是否存在一种统一的定义方式,被广大开发人员接受认可的方式呢?

这就是被普遍采用的 API 的 RESTful 设计风格.

路径

url 补充说明:

 

只能有名词,不能有动词,而且所用的名词往往与数据库的表名对应.

GET   /products/4 :前端获取后端的单个产品(4号商品)
GET   /products :  前端获取后端的所有产品

POST  /products :  前端发给后端数据保存到后端
PUT   /products/4 :前端修改后端保存的数据
DELETE /products/4 : 前端删除后端保存的4号数据

名词能够使结构简洁.

API 中的名词应该使用复数.

举例来说,获取产品的 API 可以这样定义

获取单个产品:

http:
//127.0.0.1:8080/AppName/rest/products/1
获取所有产品: 

http:
//127.0.0.1:8080/AppName/rest/products

HTTP 动词

常用的HTTP动词有下面四个(括号里是对应的 SQL 命令).

- GET :    取出服务器资源 (一项或多项)
- POST :   往服务器新增一个资源.
- PUT :    修改服务器存储的资源 (客户端需提供修改所需的完整资源)
- DELETE :  删除服务器资源

下面是一些例子:

GET /zoos: 取出所有动物园
POST /zoos:新建一个动物园(上传文件)
GET /zoos/ID:获取某个指定动物园的信息
PUT /zoos/ID:更新某个指定动物园的信息(提供该动物园的全部信息)
DELETE /zoos/ID:删除某个动物园
GET /zoos/ID/animals:取出某个指定动物园的所有动物
DELETE /zoos/ID/animals/ID:删除某个指定动物园的指定动物

2.2 用户名重复注册

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

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

1.请求方式

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

2.请求参数:路径参数

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

3.响应结果:JSON

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

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

from django.views import View
from apps.users.models import User
from django.http import JsonResponse

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

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

4.添加路由转换器

在utils包下创建一个converters.py文件

class UsernameConverter:
    """自定义路由转换器去匹配用户名"""
    # 定义匹配用户名的正则表达式
    regex = '[a-zA-Z0-9_-]{5,20}'

    def to_python(self, value):
        return str(value)

在总路由中添加路由转换器

from django.contrib import admin
from django.urls import path,include

from utils.converters import UsernameConverter
from django.urls import register_converter

register_converter(UsernameConverter,'username')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('apps.users.urls'))
]

在子应用中调用验证

from django.urls import path
from . import views

urlpatterns = [
    # 判断用户名是否重复
    path('usernames/<username:username>/count/',views.UsernameCountView.as_view()),
]

 2.3 跨域CORS

我们的前端和后端分别是两个不同的端口

位置域名
前端服务www.meiduo.site:8080
后端服务www.meiduo.site:8000

现在,前端与后端分处不同的域名,这就涉及到跨域访问数据的问题,因为浏览器的同源策略,默认是不支持两个不同域间相互访问数据,而我们需要在两个域名间相互传递数据,这时我们就要为后端添加跨域访问的支持。

我们使用CORS来解决后端对跨域访问的支持。

使用django-cors-headers扩展

参考文档https://github.com/ottoyiu/django-cors-headers/

安装

pip install django-cors-headers

添加应用

INSTALLED_APPS = (
    ...
    'corsheaders',
    ...
)

中间层设置

MIDDLEWARE = [
    'corsheaders.middleware.CorsMiddleware',
    ...
]

添加白名单

# CORS
CORS_ORIGIN_WHITELIST = (
    'http://127.0.0.1:8080',
    'http://localhost:8080',
    'http://www.meiduo.site:8080',
    'http://www.meiduo.site:8000'
)
CORS_ALLOW_CREDENTIALS = True  # 允许携带cookie
  • 凡是出现在白名单中的域名,都可以访问后端接口
  • CORS_ALLOW_CREDENTIALS 指明在跨域访问中,后端是否支持对cookie的操作。

2.4 手机号重复注册(作业)

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

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

1.请求方式

选项方案
请求方法GET
请求地址/mobiles/(?P<mobile>1[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 JsonResponse({'code': 0, 'errmsg': 'OK', 'count': count})

4.添加路由转换器

在utils包下的converters.py文件添加转换器

class MobileConverter:
    """自定义路由转换器去匹配手机号"""
    # 定义匹配手机号的正则表达式
    regex = '1[3-9]\d{9}'

    def to_python(self, value):
        # to_python:将匹配结果传递到视图内部时使用
        return str(value)

在总路由中添加路由转换器

from django.contrib import admin
from django.urls import path,include

from utils.converters import UsernameConverter
from django.urls import register_converter

register_converter(UsernameConverter,'username')

urlpatterns = [
    path('admin/', admin.site.urls),
    path('',include('apps.users.urls'))
]

在子应用中调用验证

from django.urls import path
from . import views

urlpatterns = [
    # 判断用户名是否重复
    path('usernames/<username:username>/count/',views.UsernameCountView.as_view()),
]

 2.5 用户注册业务逻辑分析

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

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

1. 用户注册接口设计

1.请求方式

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

2.请求参数:JSON

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

3.响应结果:JSON

响应结果响应内容
code响应码 0 表示成功 400表示失败
errmsg返回信息

2. 用户注册接口定义

1.注册视图

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

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

2.总路由

from django.contrib import admin
from django.urls import path,include

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('apps.users.urls')),
]

3.子路由

urlpatterns = [
    # 注册
    path('register/', views.RegisterView.as_view()),
]

 2.7 用户注册后端逻辑

1. 接收参数

  import json
  # 1.接收参数:请求体中的JSON数据 request.body
  json_bytes = request.body  # 从请求体中获取原始的JSON数据,bytes类型的
  json_str = json_bytes.decode()  # 将bytes类型的JSON数据,转成JSON字符串
  json_dict = json.loads(json_str)  # 将JSON字符串,转成python的标准字典
  # json_dict = json.loads(request.body.decode())

  # 提取参数
  username = json_dict.get('username')
  password = json_dict.get('password')
  password2 = json_dict.get('password2')
  mobile = json_dict.get('mobile')
  allow = json_dict.get('allow')
  sms_code = json_dict.get('sms_code')

2. 校验参数

from django import http
import re

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

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

3. 保存注册数据,返回相应

 try:
    user = User.objects.create_user(username=username,
                                    password=password,
                                    mobile=mobile)
except Exception as e:
    return http.JsonResponse({'code': 400, 'errmsg': '注册失败!'})


return http.JsonResponse({'code': 0, 'errmsg': '注册成功!'})
  • 这里使用Django认证系统用户模型类提供的create_user()方法创建新的用户。
  • 这里create_user()方法中封装了set_password()方法加密密码。

注意

我们通过postman或者浏览器验证的时候回出现CSRF Forbidden问题

 

解决CSRF Forbidden问题, 关闭csrf中间件

2.8 状态保持

说明:

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

美多商城的需求是:注册成功后即表示用户认证通过

1. login()方法介绍

  1. 状态保持:
    • 将通过认证的用户的唯一标识信息(比如:用户ID)写入到当前session会话中
  2. login()方法:
    • Django用户认证系统提供了 login() 方法
    • 封装了写入session的操作,帮助我们快速实现状态保持
  3. login()位置:

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

      login(request, user)
      

2. login()方法使用

# 保存注册数据
try:
    user = User.objects.create_user(username=username, password=password, mobile=mobile)
except DatabaseError:
    return http.JsonResponse({'code': 400, 'errmsg': '注册失败!'})

# 实现状态保持
login(request, user)

# 响应注册结果
return http.JsonResponse({'code': 0, 'errmsg': '注册成功!'})

3. 查看状态保持结果

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值