【15.0】登陆注册功能
【一】多方式登陆
【1】思路分析
(1)接口设计
-
接口描述
- 用户登录接口
-
请求URL
/api/v1/user/userinfo/mul_login/
-
请求方式
- POST
-
Body请求参数(application/json)
参数名 | 必选 | 类型 | 说明 |
---|---|---|---|
username | 是 | string | 用户名(支持用户名/邮箱/手机号) |
password | 是 | string | 密码 |
- 返回示例
- 500认证成功
- 401 认证失败
{
"code": 100,
"msg": "请求成功",
"username": "admin",
"token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6ImFkbWluIiwiZXhwIjoxNjkxNTY0MTE1LCJlbWFpbCI6IiJ9.RYxs3D6EjOfzLKGgF-QAav6k0sC_tCPWUd6tskGdlhI",
"icon": "http://127.0.0.1:8000/media/icon/default.png"
}
- 要求
- 校验参数是否为空
- 校验账号密码是否正确
- 登陆之后返回token
- 支持用户名多字段登陆,用户名可以使用手机号/邮箱/用户名登陆
【2】代码实现
- 视图层
luffyCity\luffyCity\apps\user\views.py
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
from luffyCity.apps.user.models import User
from luffyCity.apps.user.serializers.mul_login_serializer import MulLoginSerializer
from luffyCity.utils.common_response import CommonResponse
from rest_framework.exceptions import APIException
# Create your views here.
class UserView(GenericViewSet):
'''
验证手机号接口
get请求
与数据库交互但不需要序列化
继承 ViewSet 自动生成路由
'''
# 序列化类
serializer_class = MulLoginSerializer
# 校验手机号
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
'''
get 请求 携带在地址参数
:param request:
:param args:
:param kwargs:
:return:
'''
try:
mobile = request.query_params.get('mobile', None)
User.objects.get(mobile=mobile) # 有且只有一条才不会报错
return CommonResponse(msg="手机号存在")
except Exception as e:
raise APIException("手机号不存在")
# 多方式登陆 --- 序列化类校验数据
@action(methods=['POST'], detail=False)
def mul_login(self, request, *args, **kwargs):
# 校验逻辑 --- 序列化类
ser = self.get_serializer(data=request.data)
# raise_exception:如果有错误,主动抛出异常,被全局异常捕获
# is_valid : 触发字段的校验规则,局部钩子/全局钩子(全局钩子中写验证逻辑,签发token)
ser.is_valid(raise_exception=True)
username = ser.context.get('username')
token = ser.context.get('token')
icon = ser.context.get('icon')
return CommonResponse(username=username, token=token, icon=icon)
- 序列化类
luffyCity\luffyCity\apps\user\serializers\mul_login_serializer.py
# -*-coding: Utf-8 -*-
# @File : mul_login_serializer .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/9
from django.db.models import Q
from rest_framework import serializers
from ..models import User
from rest_framework.exceptions import APIException
from rest_framework_jwt.settings import api_settings
from django.conf import settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class MulLoginSerializer(serializers.ModelSerializer):
# 字段自己的规则校验,一次性校验过不去,需要重写校验规则
username = serializers.CharField(max_length=32, required=True)
class Meta:
model = User
# 只做数据校验 ---- 写校验的字段
fields = ['username', 'password']
def _get_user(self, attrs):
username = attrs.get('username')
user = User.objects.filter(Q(username=username) | Q(mobile=username) | Q(email=username)).first()
password = attrs.get('password')
if user and user.check_password(password):
# 用户存在且密码正确
return user
else:
raise APIException("用户名或密码错误")
def _get_token(self, user):
# 签发token --- JWT
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return token
def validate(self, attrs):
# 验证用户密码逻辑 ---- 签发token
# username 字段可能是 用户/手机号/邮箱 ---- 正则/Q查询
user = self._get_user(attrs)
# 校验成功 签发token
token = self._get_token(user)
# 用户名和token放在context(上下文管理器)中
self.context['username'] = user.username
self.context['icon'] = settings.BACKEND_URL + str(user.icon.url)
self.context['token'] = token
# attrs : 字典格式,校验通过的数据
return attrs
luffyCity\luffyCity\utils\common_settings.py
BACKEND_URL = 'http://127.0.0.1:8000'
- 路由
luffyCity\luffyCity\apps\user\urls.py
from django.urls import path
from .views import UserView
from rest_framework.routers import SimpleRouter
router = SimpleRouter()
router.register('userinfo', UserView, 'userinfo')
urlpatterns = [
]
urlpatterns += router.urls
【二】验证码接口封装成包
【1】验证码发送主函数
luffyCity\luffyCity\libs\SMS_TencentCloud_Sender\SMS_Ten_Send.py
# -*-coding: Utf-8 -*-
# @File : SMS_Ten_Send .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/9
import os
# -*- coding: utf-8 -*-
from tencentcloud.common import credential
from tencentcloud.common.exception.tencent_cloud_sdk_exception import TencentCloudSDKException
from tencentcloud.sms.v20210111 import sms_client, models
from tencentcloud.common.profile.client_profile import ClientProfile
from tencentcloud.common.profile.http_profile import HttpProfile
import random
from . import settings
def get_verify_code(circle_bum):
code = ''
for i in range(circle_bum):
code += str(random.randint(0, 9))
return code
class SMS_TencentCloud_Sender():
def __init__(self, code, phone):
# 初始化 SecretId、SecretKey (为了安全防盗,置于本地环境变量中获取)
self.cred = credential.Credential(settings.SECRET_ID, settings.SECRET_KEY)
# 下发手机号码 : 示例如:+8613711112222, 其中前面有一个+号 ,86为国家码,13711112222为手机号,最多不要超过200个手机号
self.phone = phone
# 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致,,若无模板参数,则设置为空
# 验证码发送成功,验证码为:{self.code},{self.timeout}分钟内有效!
# 目标验证码 , 目标超时时间(如果模板中设置了有效时间)
self.template_param_set = [f'{code}', f'{settings.FAIL_TIME}']
# APPID : 添加应用后生成的实际SdkAppId,示例如1400006666
self.appid = settings.SMS_SDK_APPID
# 必须填写已审核通过的签名
self.sign_name = settings.SIGN_NAME
# 必须填写已审核通过的模板 ID
self.template_id = settings.TEMPLATE_ID
def create_Client(self):
httpProfile = HttpProfile()
httpProfile.reqMethod = "POST" # post请求(默认为post请求)
httpProfile.reqTimeout = 30 # 请求超时时间,单位为秒(默认60秒)
httpProfile.endpoint = "sms.tencentcloudapi.com" # 指定接入地域域名(默认就近接入)
# 实例化一个客户端配置对象,可以指定超时时间等配置
clientProfile = ClientProfile()
clientProfile.signMethod = "TC3-HMAC-SHA256" # 指定签名算法
clientProfile.language = "en-US"
clientProfile.httpProfile = httpProfile
# 实例化要请求产品(以sms为例)的client对象
# 第二个参数是地域信息,可以直接填写字符串ap-guangzhou
# 支持的地域列表参考 https://cloud.tencent.com/document/api/382/52071#.E5.9C.B0.E5.9F.9F.E5.88.97.E8.A1.A8
self.client = sms_client.SmsClient(self.cred, "ap-guangzhou", clientProfile)
def create_Request(self):
# 实例化一个请求对象,根据调用的接口和实际情况,可以进一步设置请求参数
req = models.SendSmsRequest()
req.SmsSdkAppId = self.appid
req.SignName = self.sign_name
req.TemplateId = self.template_id
req.TemplateParamSet = self.template_param_set
req.PhoneNumberSet = [f"+86{self.phone}"]
# 用户的 session 内容(无需要可忽略): 可以携带用户侧 ID 等上下文信息,server 会原样返回
req.SessionContext = ""
# 短信码号扩展号(无需要可忽略): 默认未开通,如需开通请联系 [腾讯云短信小助手]
req.ExtendCode = ""
# 国内短信无需填写该项;国际/港澳台短信已申请独立 SenderId 需要填写该字段,默认使用公共 SenderId,无需填写该字段。
req.SenderId = ""
resp = self.client.SendSms(req)
# 输出json格式的字符串回包
res_dict = resp._serialize(allow_none=True)
if res_dict['SendStatusSet'][0]['Code'] == "Ok":
return True
else:
print(res_dict)
return False
def send_sms(self):
self.create_Client()
return self.create_Request()
def tencent_sms_main(verify_code, tag_phone):
try:
t_sms = SMS_TencentCloud_Sender(verify_code, tag_phone)
return t_sms.send_sms()
except Exception as e:
print(e)
return False
if __name__ == '__main__':
phone = ''
code = get_verify_code(4)
result = tencent_sms_main(code, phone)
print(result)
# print(os.environ)
【2】验证码发送配置文件
luffyCity\luffyCity\libs\SMS_TencentCloud_Sender\settings.py
# -*-coding: Utf-8 -*-
# @File : settings .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/9
import os
# 腾讯云账户密钥对 secretId
SECRET_ID = os.environ.get("TENCENTCLOUD_SECRET_ID")
# 腾讯云账户密钥对 secretKey
SECRET_KEY = os.environ.get("TENCENTCLOUD_SECRET_KEY")
# 添加应用后生成的实际SdkAppId
SMS_SDK_APPID = '1400837802'
# 必须填写已审核通过的签名
SIGN_NAME = '梦梦的知识星球公众号'
# 必须填写已审核通过的模板 ID
TEMPLATE_ID = '1891656'
# 模板参数的个数需要与 TemplateId 对应模板的变量个数保持一致
TEMPLATE_PARAM_SET = ''
# 用户的 session 内容(无需要可忽略)
SESSION_CONTEXT = ''
# 短信码号扩展号(无需要可忽略)
EXTEND_CODE = ''
# 国内短信无需填写该项
SENDER_ID = ''
# 验证码失效时间
FAIL_TIME = '2'
【3】验证码包的初始化文件
luffyCity\luffyCity\libs\SMS_TencentCloud_Sender\__init__.py
# -*-coding: Utf-8 -*-
# @File : __init__ .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/9
from .SMS_Ten_Send import get_verify_code, tencent_sms_main
【4】验证码发送接口的风险问题
验证码发送接口的风险问题主要是安全性和频率限制两个方面。
- 首先,短信验证码的安全性是一个重要的问题。
- 因为验证码通常用于身份验证或重要操作的确认,如果验证码泄露或被劫持,可能导致用户账号被盗或遭受其他安全威胁。
(1)提高安全性
数据加密:
- 在验证码发送接口中,可以引入加密机制
- 例如携带一个特定的加密串,使用对称或非对称加密算法将验证码数据进行加密,以防止数据被未授权人员获取并使用。
防止重放攻击:
- 为了防止恶意用户重复使用已经获取到的验证码进行验证,可以在验证码数据中加入一些唯一标识符或时间戳,并在验证过程中验证其有效性。
- 这样可以有效防止验证码的重放攻击。
(2)频率限制
- 其次,频率限制也是必要的。通过限制发送验证码的频率,可以降低恶意用户滥用接口或对系统造成过大负载的风险。
IP限制:
- 可以通过限制同一个IP地址在一段时间内发送验证码的次数,来限制恶意用户的行为。对于大流量代理服务器问题,可以考虑使用代理池技术,即在后台维护一个可用的代理IP池,通过轮询使用不同的IP地址发送验证码短信,以平均负载和降低单个IP的频率。
手机号限制:
- 同一个手机号在一定时间内发送验证码的次数也需要进行限制,以防止恶意用户通过滥用接口对用户账号进行猜测或攻击。可以设置一个合理的时间间隔,在此时间间隔内只允许发送有限次数的验证码。
【三】短信验证登录
【1】主视图函数
from django.shortcuts import render, HttpResponse
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.decorators import action
from luffyCity.apps.user.models import User
from luffyCity.apps.user.serializers.mul_login_serializer import MulLoginSerializer, SmsLoginSerializer
from luffyCity.utils.common_response import CommonResponse
from rest_framework.exceptions import APIException
from luffyCity.libs.SMS_TencentCloud_Sender import get_verify_code, tencent_sms_main
from django.core.cache import cache
# Create your views here.
class UserView(GenericViewSet):
'''
验证手机号接口
get请求
与数据库交互但不需要序列化
继承 ViewSet 自动生成路由
'''
# 序列化类
serializer_class = MulLoginSerializer
# 校验手机号
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
'''
get 请求 携带在地址参数
:param request:
:param args:
:param kwargs:
:return:
'''
try:
mobile = request.query_params.get('mobile', None)
User.objects.get(mobile=mobile) # 有且只有一条才不会报错
return CommonResponse(msg="手机号存在")
except Exception as e:
raise APIException("手机号不存在")
def _common_login(self, request, *args, **kwargs):
# 校验逻辑 --- 序列化类
ser = self.get_serializer(data=request.data)
# raise_exception:如果有错误,主动抛出异常,被全局异常捕获
# is_valid : 触发字段的校验规则,局部钩子/全局钩子(全局钩子中写验证逻辑,签发token)
ser.is_valid(raise_exception=True)
username = ser.context.get('username')
token = ser.context.get('token')
icon = ser.context.get('icon')
return CommonResponse(username=username, token=token, icon=icon)
# 多方式登陆 --- 序列化类校验数据
@action(methods=['POST'], detail=False)
def mul_login(self, request, *args, **kwargs):
return self._common_login(request, *args, **kwargs)
@action(methods=['GET'], detail=False)
def send_sms(self, request, *args, **kwargs):
# 前端把需要发送验证码的手机号传入,携带在地址栏中
mobile = request.query_params.get('mobile', None)
code = get_verify_code(4) # 存储验证码,放到缓存内
cache.set(f'sms_code_{mobile}', code)
if mobile and tencent_sms_main(verify_code=code, tag_phone=mobile):
return CommonResponse(msg="发送验证码成功")
raise APIException("请输入手机号")
def get_serializer_class(self):
if self.action == 'sms_login':
return SmsLoginSerializer
else:
return self.serializer_class
@action(methods=['POST'], detail=False)
def sms_login(self, request, *args, **kwargs):
return self._common_login(request, *args, **kwargs)
【短信发送功能优化】异步处理
原来的发送短信,是同步
- 前端输入手机号---》点击发送短信---》前端发送ajax请求----》到咱们后端接口---》取出手机号----》调用腾讯发送短信---》腾讯去发短信---》发完后----》回复给我们后端发送成功---》我们后端收到发送成功---》给我们前端返回发送成功
把腾讯发送短信的过程,变成异步
- 前端输入手机号---》点击发送短信---》前端发送ajax请求----》到咱们后端接口---》取出手机号----》开启线程,去调用腾讯短信发送(异步)---》我们后端继续往后走----》直接返回给前端,告诉前端短信已发送
-另一条发短信线程线程会去发送短信,至于是否成功,我们不管了
@action(methods=['GET'], detail=False)
def send_sms(self, request, *args, **kwargs):
# 前端把需要发送验证码的手机号传入,携带在地址栏中
mobile = request.query_params.get('mobile', None)
code = get_verify_code(4) # 存储验证码,放到缓存内
cache.set(f'sms_code_{mobile}', code)
if mobile:
# 开启线程处理短信
# tencent_sms_main(verify_code=code, tag_phone=mobile)
t = Thread(target=tencent_sms_main, args=(code, mobile,))
t.start()
return CommonResponse(msg="验证码已发送")
raise APIException("请输入手机号")
【2】序列化校验
# -*-coding: Utf-8 -*-
# @File : mul_login_serializer .py
# author: Chimengmeng
# blog_url : https://www.cnblogs.com/dream-ze/
# Time:2023/8/9
from django.db.models import Q
from rest_framework import serializers
from ..models import User
from rest_framework.exceptions import APIException
from rest_framework_jwt.settings import api_settings
from django.conf import settings
from django.core.cache import cache
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
class CommonLoginSerializer():
def _get_user(self, attrs):
username = attrs.get('username')
user = User.objects.filter(Q(username=username) | Q(mobile=username) | Q(email=username)).first()
password = attrs.get('password')
if user and user.check_password(password):
# 用户存在且密码正确
return user
else:
raise APIException("用户名或密码错误")
def _get_token(self, user):
# 签发token --- JWT
payload = jwt_payload_handler(user)
token = jwt_encode_handler(payload)
return token
def validate(self, attrs):
# 验证用户密码逻辑 ---- 签发token
# username 字段可能是 用户/手机号/邮箱 ---- 正则/Q查询
user = self._get_user(attrs)
# 校验成功 签发token
token = self._get_token(user)
# 用户名和token放在context(上下文管理器)中
self.context['username'] = user.username
self.context['icon'] = settings.BACKEND_URL + str(user.icon.url)
self.context['token'] = token
# attrs : 字典格式,校验通过的数据
return attrs
class MulLoginSerializer(CommonLoginSerializer, serializers.ModelSerializer):
# 字段自己的规则校验,一次性校验过不去,需要重写校验规则
username = serializers.CharField(max_length=32, required=True)
class Meta:
model = User
# 只做数据校验 ---- 写校验的字段
fields = ['username', 'password']
def _get_user(self, attrs):
username = attrs.get('username')
user = User.objects.filter(Q(username=username) | Q(mobile=username) | Q(email=username)).first()
password = attrs.get('password')
if user and user.check_password(password):
# 用户存在且密码正确
return user
else:
raise APIException("用户名或密码错误")
class SmsLoginSerializer(CommonLoginSerializer, serializers.Serializer):
code = serializers.CharField(max_length=4)
mobile = serializers.CharField(max_length=11)
def _get_user(self, attrs):
# 从attrs中取出手机号和验证码
# 验证验证码是否正确
mobile = attrs.get('mobile')
code = attrs.get('code')
old_code = cache.get(f'sms_code_{mobile}')
# 测试环节,高并发 DEBUG 开启并且给一个万能的验证码
if code == old_code or (settings.DEBUG and code == '999'):
# 验证码正确 , 查询用户
user = User.objects.filter(mobile=mobile).first()
if user:
return user
else:
raise APIException("手机号不存在")
else:
raise APIException("验证码错误")
【四】注册功能
【2】功能实现
- 视图函数
luffyCity\luffyCity\apps\user\views.py
from threading import Thread
from django.shortcuts import render, HttpResponse
from rest_framework.viewsets import ViewSet, GenericViewSet
from rest_framework.mixins import CreateModelMixin
from rest_framework.decorators import action
from luffyCity.apps.user.models import User
from luffyCity.apps.user.serializers.mul_login_serializer import MulLoginSerializer, SmsLoginSerializer, \
UserRegisterSerializer
from luffyCity.utils.common_response import CommonResponse
from rest_framework.exceptions import APIException
from luffyCity.libs.SMS_TencentCloud_Sender import get_verify_code, tencent_sms_main
from django.core.cache import cache
# Create your views here.
class UserView(GenericViewSet, CreateModelMixin):
'''
验证手机号接口
get请求
与数据库交互但不需要序列化
继承 ViewSet 自动生成路由
'''
# 序列化类
serializer_class = MulLoginSerializer
# 校验手机号
@action(methods=['GET'], detail=False)
def check_mobile(self, request, *args, **kwargs):
'''
get 请求 携带在地址参数
:param request:
:param args:
:param kwargs:
:return:
'''
try:
mobile = request.query_params.get('mobile', None)
User.objects.get(mobile=mobile) # 有且只有一条才不会报错
return CommonResponse(msg="手机号存在")
except Exception as e:
raise APIException("手机号不存在")
def _common_login(self, request, *args, **kwargs):
# 校验逻辑 --- 序列化类
ser = self.get_serializer(data=request.data)
# raise_exception:如果有错误,主动抛出异常,被全局异常捕获
# is_valid : 触发字段的校验规则,局部钩子/全局钩子(全局钩子中写验证逻辑,签发token)
ser.is_valid(raise_exception=True)
username = ser.context.get('username')
token = ser.context.get('token')
icon = ser.context.get('icon')
return CommonResponse(username=username, token=token, icon=icon)
# 多方式登陆 --- 序列化类校验数据
@action(methods=['POST'], detail=False)
def mul_login(self, request, *args, **kwargs):
return self._common_login(request, *args, **kwargs)
# @action(methods=['GET'], detail=False)
# def send_sms(self, request, *args, **kwargs):
#
# # 前端把需要发送验证码的手机号传入,携带在地址栏中
# mobile = request.query_params.get('mobile', None)
# code = get_verify_code(4) # 存储验证码,放到缓存内
# cache.set(f'sms_code_{mobile}', code)
# if mobile and tencent_sms_main(verify_code=code, tag_phone=mobile):
# return CommonResponse(msg="发送验证码成功")
# raise APIException("请输入手机号")
@action(methods=['GET'], detail=False)
def send_sms(self, request, *args, **kwargs):
# 前端把需要发送验证码的手机号传入,携带在地址栏中
mobile = request.query_params.get('mobile', None)
code = get_verify_code(4) # 存储验证码,放到缓存内
cache.set(f'sms_code_{mobile}', code)
if mobile:
# 开启线程处理短信
# tencent_sms_main(verify_code=code, tag_phone=mobile)
t = Thread(target=tencent_sms_main, args=(code, mobile,))
t.start()
return CommonResponse(msg="验证码已发送")
raise APIException("请输入手机号")
def get_serializer_class(self):
if self.action == 'sms_login':
return SmsLoginSerializer
elif self.action == 'register' or self.action == 'create':
return UserRegisterSerializer
else:
return self.serializer_class
@action(methods=['POST'], detail=False)
def sms_login(self, request, *args, **kwargs):
return self._common_login(request, *args, **kwargs)
# 自己写的 访问:127.0.0.1:8000/api/v1/user/userinfo/register/ --->post请求即可
@action(methods=['POST'], detail=False)
def register(self, request, *args, **kwargs):
ser = self.get_serializer(data=request.data)
ser.is_valid(raise_exception=True)
ser.save()
# super().create(request, *args, **kwargs) # 只要这样写,又会走序列化
return CommonResponse(msg='注册成功')
# 不自己写了,只要继承CreateModelMixin,访问:127.0.0.1:8000/api/v1/user/userinfo --->post请求即可
# 这个我们不用写,它有 只要post请求过来,就会执行create
# def create(self, request, *args, **kwargs):
# serializer = self.get_serializer(data=request.data) # 第一个错误 UserRegisterSerializer
# serializer.is_valid(raise_exception=True) #执行三个校验:字段自己,局部钩子,全局
# self.perform_create(serializer)
# # 序列化要调用它,只要调用serializer.data ,就会走序列化,只要走序列化,会把create返回的user对象 来使用UserRegisterSerializer类做序列化
# return CommonResponse(msg='注册成功') #不走序列化了,序列类中得write_only 也就不用了
- 序列化类
luffyCity\luffyCity\apps\user\serializers\mul_login_serializer.py
# 注册:1 校验数据 2 保存 3 序列化用不要?存疑
class UserRegisterSerializer(serializers.ModelSerializer):
code = serializers.CharField(max_length=4, min_length=4, write_only=True)
class Meta:
model = User
fields = ['mobile', 'password', 'code'] # code 不是数据库的字段,需要重写
# 如果要限制密码强度,需要写个局部钩子
def _check_code(self, attrs):
mobile = attrs.get('mobile')
code = attrs.get('code')
old_code = cache.get('send_sms_code_%s' % mobile)
if not (code == old_code or (settings.DEBUG and code == '9999')): # 第二个错误:debug忘了设为True
raise APIException("验证码错误")
def _pre_save(self, attrs): # {mobile:122222,code:8888,password:123}
attrs.pop('code')
attrs['username'] = attrs.get('mobile') # 默认用户名就是手机号 可以随机生成用户名 随机生成有意义的名字( Faker)
def validate(self, attrs):
# 写逻辑
# 1 校验验证码是否正确
self._check_code(attrs)
# 2 入口前准备 ---》code不是数据库字段,不能入库,username是数据库字段必填,这里没有,写成默认
self._pre_save(attrs)
return attrs
def create(self, validated_data): # {mobile:122222,password:123,username:名字}
# 为什么要重写create? 因为密码人家是加密的,如果不写用的是
# User.objects.create(**validated_data) # 密码是铭文,必须重写
user = User.objects.create_user(**validated_data) # 保存成功,密码就是加密的
return user
本文来自博客园,作者:Chimengmeng,转载请注明原文链接:https://www.cnblogs.com/dream-ze/p/17642726.html