美多商城项目 02用户注册
Posted 黑马程序员官方
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了美多商城项目 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)
- 设置密码:
- User对象基本属性
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. 知识要点
- Django自带用户认证系统,核心就是User对象。
- Django用户认证系统包含了一系列对用户的操作,比如:模型类,认证,权限,分组,密码处理等。
- Django用户认证系统中的用户模型类可以自定义,继承自AbstractUser。
- 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. 知识要点
- 用户认证系统中的用户模型类,是通过全局配置项AUTH_USER_MODEL决定的。
- 如果迁移自定义用户模型类,必须先配置 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.请求参数:路径参数
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
username | string | 是 | 用户名 |
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]\\d9)/count/ |
2.请求参数:路径参数
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
mobile | string | 是 | 手机号 |
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]\\d9'
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
参数名 | 类型 | 是否必传 | 说明 |
---|---|---|---|
username | string | 是 | 用户名 |
password | string | 是 | 密码 |
password2 | string | 是 | 确认密码 |
mobile | string | 是 | 手机号 |
sms_code | string | 是 | 短信验证码 |
allow | string | 是 | 是否同意用户协议 |
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]\\d9$', 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()方法介绍
- 状态保持:
- 将通过认证的用户的唯一标识信息(比如:用户ID)写入到当前session会话中
- login()方法:
- Django用户认证系统提供了
login()
方法 - 封装了写入session的操作,帮助我们快速实现状态保持
- Django用户认证系统提供了
-
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. 查看状态保持结果
以上是关于美多商城项目 02用户注册的主要内容,如果未能解决你的问题,请参考以下文章