前言:
登陆和注册功能是一个功能比较完善的网站必备的功能,其中涉及的业务逻辑实用性较强,所以我将Django的注册功能进行了总结,希望可以帮助大家。我们这次使用的第三方短息平台是云通信,当然你可以用其他的第三方平台,我使用这个平台的主要原因是 云通信有免费的试用。云通信的官方文档链接:http://www.yuntongxun.com/doc/ready/demo/1_4_1_2.html,图片验证码是使用的captcha包,这个包可以在git开源社区直接下载 ,如果你有其他更加高大上的验证码模块的可以使用也可以使用,基本的业务逻辑是不变的。
1.准备工作:(1)下载官方API文件,由于这些东西官方已经帮你编写完成了,因此可以直接拿来用,节省了开发时间。将下载的官方的文件复制到你的项目中
你可以向我一样在apps(项目子应用目录)的同级目录下创建一个libs的模块包用来存放第三方的包,这样可以让项目的目录更加的清晰,维护起来也比较方便,做到这里基本的准备工作就完成了
(2)在apps模块中创建usrs子应用和verifications子应用,创建方法:在终端执行 python manage.py startapp users/verifications(注意必须在manage.py的目录下执行),这是你创建的子应用并不在apps目录下而是和apps同级目录,你需要手动将users子应用移动到apps中。做完这些你的准备工作就完成了
2.注册路由 :
(1)在主工程的urls文件添加以下信息
(2)在子应用中创建urls.py文件(用来作为路由的二次引导),这里我就以users为例,verifications的做法一样
3.判断用户名是否重复:
通常的开发环境下,我们认为用户名是不能重复的,因此我们需要写一个api接口验证用户民给是否存在。
在users子模块views中编写用户名验重代码
# 验证用户名接口
class RegisterUsernameCountAPIView(APIView):
# /users/usernames/(?P\w{5,20})/count/
def get(self,request,username):
# 查询数据
count = User.objects.filter(username=username).count()
context = {
#count=0没有,count=1有
"count":count, "username":username, } return Response(context)
将api的url注册到urls中
url(r'^usernames/(?P\w{5,20})/count/$',views.RegisterUsernameCountAPIView.as_view()),
4.校验手机号码或邮箱
手机号码或者与邮箱必须是唯一的,将他们设置成唯一的在用户更改信息时对用户身份尽心验证,这样会更加的安全,由于这两个api基本一样,我们在这里以手机号码为例:
在users子模块views中编写代码
# 验证用户名电话
class RegisterModileCountAPIView(APIView):
# /users/mobile/(?P1[345789]\d{9})/count/
def get(self,request,mobile):
# 查询数据
count = User.objects.filter(mobile=mobile).count()
context = {
#count=0没有,count=1有
"count":count,
"mobile":mobile,
}
return Response(context)
将api注册到urls中
url(r'^mobile/(?P1[345789]\d{9})/count/',views.RegisterMobileCountAPIView.as_view()),
好了我们已经进行了一些简单的验证,接下来我们将会通过图片验证与短信验证来进一步完善我们的代码
5.图形验证码
一个安全可靠的注册界面一些必要的验证手段是必不可少的,我们写的注册模块利用了图形验证码与短信验证码,首先我们需要先获取图形验证码,,在 veriifications子应用中的views中编写获取验证码代码:
from rest_framework.views import APIView
from django.http import HttpResponse
from libs.captcha.captcha import captcha
from django_redis import get_redis_connection
class VerificationAPIView(APIView):
# /verifications/imagecodes/(?P.+)/
def get(self,request,image_code_id):
# 获取验证码
text,image_code = captcha.generate_captcha()
# 将验证码存储到redis中
redis = get_redis_connection('code')
redis.setex('img_%s'%image_code_id,200,text)
return HttpResponse(content_type='image/png',content=image_code)
这里我们是使用redis数据库存储每次获取的验证码,在使用redis之前我们在settings中添加对验证的redis支持:
#Redis
CACHES = {
... ,
"code": {
"BACKEND": "django_redis.cache.RedisCache",
"LOCATION": "redis://127.0.0.1:6379/2",
"OPTIONS": {
"CLIENT_CLASS": "django_redis.client.DefaultClient",
}
}
}
除了setting配置之外我们还需要注意我们在给前端发出响应的时候需要在HttpResponse(content_type='image/png',content=image_code)设置数据类型content-type,不然浏览器会普通的json格式的数据解析,会出现乱码。setting设置完成后将图片验证码的url注册到verifications中
# /verifications/imagecodes/(?P.+)/ 验证码
url(r'^imagecodes/(?P.+)/$',views.VerificationAPIView.as_view()),
接下来测试下我们的代码:
现在图形验证码就做好了,我们只需要将前端的img标签的src属性的值改为对应的url地址就行了,放在表单里的效果图(随便找的一个注册表单)
6. 短信验证码
拥有图形验证验证码后我们的注册就有了第一层的保障,但这些还是完全不够的,我们还需要短信验证码进一步验证,首先我们需要在在veriifications子应用中的views中编写获取验证码代码:
class SmscodesAPIView(APIView):
# /verifications/smscodes/(?P1[345789]\d{9})/?text=xxxx & image_code_id=xxxx
def get(self,request,mobile):
# 获取验证码
print(1)
data= request.query_params
print(data)
# 创建并调用序列化器
value = SmscodesSerializer(data=data)
value .is_valid(raise_exception=True)
# 生成短信验证码
smscode = '%06d'%randint(100000,999999)
# 将验证码存入redis
sms_redis = get_redis_connection('smscode')
sms_redis.setex('sms_%s'%mobile,5*60,smscode)
# 利用celery实现异步发送短信验证码
from celery_tasks.sms.tasks import send_sms_code
# 注意不能直接调用,必须先调用delay()方法
send_sms_code.delay(mobile, smscode)
return Response({'message': 'ok'})
这里我们利用了celery 实现短信的异步发布,详情请参考:https://www.cnblogs.com/xuchuankun/p/9787786.html
然后在veriifications子应用中创建serializer文件,这个文件就是我们的序列化器,这是django对数据处理的一整个十分重要的途径,也充分的体现了面向对象的编程思想
from rest_framework import serializers
from django_redis import get_redis_connection
class SmscodesSerializer(serializers.Serializer):
# 需要验证的字段 text(输入的验证码),image_code_id
text = serializers.CharField(max_length=4,min_length=4,required=True,label="验证码")
image_code_id = serializers.UUIDField(label="uuid")
def validate(self,attrs):
text = attrs.get("text")
image_code_id = attrs.get("image_code_id")
# 链接redis
redis = get_redis_connection('code')
redis_text = redis.get('img_%s'%image_code_id)
#判断验证码是否过期
if redis_text is None:
raise serializers.ValidationError('验证码已过期')
# 判断验证码与保存在redis的是否一直
if redis_text.decode().lower() != text.lower():
raise serializers.ValidationError('验证码不一致')
return attrs
我们创建的序列化器直接让我们的序列化器继承了serializers.Serializer类,这样为我们省去了许多的时间,但这种方法必须在models类已经创建的情况下才能使用,虽然方便但也由一定的
限制。如果你没有创建models类,我们可以让序列化器继承serializers.ModelSerializer,虽然比较麻烦但没有限制,我们这次采用第一种方法,另外附上models文件
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 = 'md_users'
verbose_name = '用户'
verbose_name_plural = verbose_name
这中方法也采用了继承Django内置的AbstractUser的方法,然后在此基础上进行修改。最后我们要把api注册到veriifications路由中
url(r'^smscodes/(?P1[345789]\d{9})/$',views.SmscodesAPIView.as_view()),
做到这里我们基本的一些准备工作已经完成了,接下来就要实现注册功能了,详情请看我下一篇博客,。谢谢大家