Django认证系统中提供的用户模型类及方法很方便,我们可以使用这个模型类,但是字段有些无法满足项目需求,如本项目中需要保存用户的手机号,需要给模型类添加额外的字段。
我们需要继承抽象模型类django.contrib.auth.models.AbstractUser,并新增手机号码字段。
(1).在meiduo_mall/meiduo_mall/apps中创建Django应用users,并在配置文件中注册users应用
# 1.终端进入虚拟环境--进入apps路径操作
python manage.py startapp users
# 2.pycharm中工程下dev.py中注册应用
INSTALLED_APPS = [
...
'users.apps.UsersConfig',
]
(2).在users应用下的models.py中定义用户的模型类
from django.contrib.auth.models import AbstractUser
from django.db import models
# 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
(3).在配置文件dev.py中告知Django认证系统使用我们自定义的模型类。
AUTH_USER_MODEL = 'users.User'
AUTH_USER_MODEL
参数的设置以点.
来分隔,表示应用名.模型类名
,且只能出现一个.,所以前边才需要设置导包路径。
注意:Django建议我们对于AUTH_USER_MODEL参数的设置一定要在第一次数据库迁移之前就设置好,否则后续使用可能出现未知错误,如设置密码但登陆出错。
(4).终端中manage.py同级目录执行数据库迁移命令
python manage.py makemigrations
python manage.py migrate
在用户注册中,需要实现以下接口:
图片验证码、短信验证码考虑到后续可能会在其他业务中也用到,因此我们将图片验证码独立。
在meiduo_mall/meiduo_mall/apps创建一个新应用verifications并注册到配置文件dev.py,在此应用中实现图片验证码、短信验证码
# 1.在指定虚拟环境下,进入apps路径,创建子应用
python manage.py startapp verifications
# 2.在dev.py注册子应用verifications
INSTALLED_APPS = [
...
'verifications.apps.VerificationsConfig',
]
访问方式:
GET /image_codes/(?P\w{8}(-\w{4}){3}-\w{12})/
请求参数: 路径参数
参数 | 类型 | 是否必须 | 说明 |
---|---|---|---|
image_code_id | uuid字符串 | 是 | 图片验证码编号 |
返回数据:验证码图片
1.将图片验证码第三方库文件captcha复制到libs目录下。
2.在verifications/views.py中,
import logging
from django.http import HttpResponse
from rest_framework import status
from rest_framework.views import APIView
from meiduo_mall.libs.captcha.captcha import captcha
from django_redis import get_redis_connection
from . import constants
# 获取在配置文件中定义的logger日志器,用来记录日志
logger = logging.getLogger('django')
# GET /image_codes/(?P[\w-]+)/
class ImageCodeView(APIView):
"""图片验证码"""
def get(self, request, image_code_id):
# 接收参数(路径参数,直接接收)
# 校验参数(路由正则表达式验证uuid格式,无需序列化器进行验证)
# 1.生成图片验证码
text, image = captcha.generate_captcha()
# 2.获取redis连接对象,并保存图片验证码真实结果
redis_conn = get_redis_connection('verify_codes')
redis_conn.setex("img_%s" % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
# 3.固定返回验证码图片数据,不需要REST framework框架的Response帮助我们决定返回响应数据的格式
# 所以此处直接使用Django原生的HttpResponse即可
# return HttpResponse(content=响应体, content_type=响应体数据类型, status=状态码)
return HttpResponse(content=image, content_type='image/jpg', status=200)
# 浏览器测试示例:http://api.meiduo.site:8000/image_codes/ed96d5ca-c88e-4a64-b1fb-52ccd8810f00/
如果想使用DRF的Response,需要自己设置图片渲染器,并添加到配置文件当中:
# utils/renders.py
from rest_framework import renderers
class JPEGRenderer(renderers.BaseRenderer):
media_type = 'image/jpeg'
format = 'jpg'
charset = None
render_style = 'binary'
def render(self, data, media_type=None, renderer_context=None):
return data
此时,可以更改图片验证码的代码:
from meiduo_mall.utils.renders import JPEGRenderer
class ImageCodeView(APIView):
renderer_classes = [JPEGRenderer]
def get(self, request: Request, image_code_id):
"""
:param request:
:param image_code_id: 图片id
:return:
"""
# 调用第三方包生成图片验证码
text, image = captcha.generate_captcha()
# 将图片验证码保存到reids数据库
redis_conn = get_redis_connection('verify_codes')
redis_conn.setex('img_%s' % image_code_id, constants.IMAGE_CODE_REDIS_EXPIRES, text)
return Response(image, content_type='image/jpeg')
3.django-redis提供了get_redis_connection的方法,通过调用get_redis_connection方法传递redis的配置名称可获取到redis的连接对象,通过redis连接对象可以执行redis命令。
我们需要在配置文件中添加一个新的redis配置,用于存放验证码数据
CACHES = {
"default": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.211.55.5:6379/0",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"session": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.211.55.5:6379/1",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
},
"verify_codes": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://10.211.55.5:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
4.在verifications中新增constants.py文件,添加常量。
# 图片验证码redis中存放的有效期,单位秒(默认5分钟)
IMAGE_CODE_REDIS_EXPIRES = 5 * 60
# 短信验证码在redis的有效期,单位秒
SMS_CODE_REDIS_EXPIRES = 5 *60
5.在verifications子应用中新增url.py文件,在其中注册图片验证码视图路由
from django.conf.urls import url
from . import views
urlpatterns = [
url(r'^image_codes/(?P\w{8}(-\w{4}){3}-\w{12})/$' , views.ImageCodeView.as_view()),
]
6.在meiduo_mall/urls.py中注册子应用verifications路由
from django.conf.urls import url, include
from django.contrib import admin
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'', include('verifications.urls')),
]
我们现在为前端和后端分别设置两个不同的域名
位置 | 域名 |
---|---|
前端 | www.meiduo.site |
后端 | api.meiduo.site |
编辑/etc/hosts
文件,可以设置本地域名
sudo vim /etc/hosts
在文件中增加两条信息(i 进入编辑模式,esc退出编辑模式,:wq 保存退出)
127.0.0.1 api.meiduo.site
127.0.0.1 www.meiduo.site
windows系统中若设置本地域名,hosts文件在如下目录:
C:\Windows\System32\drivers\etc
我们在前端front_end_pc/js目录中,创建host.js文件用以为前端保存后端域名
var host = 'http://api.meiduo.site:8000';
在所有需要访问后端接口的前端页面中都引入host.js,使用host
变量即可指代后端域名。
一旦不再使用127.0.0.1访问Django后端,需要在配置文件中修改ALLOWED_HOSTS,增加可以访问后端的域名
ALLOWED_HOSTS = [
'api.meiduo.site',
'127.0.0.1',
'localhost',
'www.meiduo.site'
]
js/register.js
data: {
...
image_code_id: '', // 图片验证码编号
image_code_url: '', // 验证码图片路径
},
mounted: function() {
this.generate_image_code();
},
methods: {
// 生成uuid
generate_uuid: function(){
var d = new Date().getTime();
if(window.performance && typeof window.performance.now === "function"){
d += performance.now(); //use high-precision timer if available
}
var uuid = 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = (d + Math.random()*16)%16 | 0;
d = Math.floor(d/16);
return (c =='x' ? r : (r&0x3|0x8)).toString(16);
});
return uuid;
},
// 生成一个图片验证码的编号,并设置页面中图片验证码img标签的src属性
generate_image_code: function(){
// 生成一个编号
// 严格一点的使用uuid保证编号唯一, 不是很严谨的情况下,也可以使用时间戳
this.image_code_id = this.generate_uuid();
// 设置页面中图片验证码img标签的src属性
this.image_code_url = this.host + "/image_codes/" + this.image_code_id + "/";
},
...
}