一、创建用户模型

  1. from django.db import models
  2. from django.contrib.auth.models import AbstractUser
  3. class User(AbstractUser):
  4. mobile = models.CharField(max_length=11, unique=True, verbose_name='手机号')
  5. class Meta:
  6. db_table = 'tb_users'
  7. verbose_name = '用户'
  8. verbose_name_plural = verbose_name
  9. def __str__(self):
  10. return self.username

在settings.py文件中指定用户模型类(AUTH_USER_MODEL = ‘app应用名.模型类名’)

  1. AUTH_USER_MODEL = 'users.User'

二、用户注册接口

  1. from django.http import JsonResponse
  2. from django.views import View
  3. from .models import User
  4. import logging
  5. logger = logging.getLogger('django')
  6. # 验证用户名重复
  7. class UsernameCountView(View):
  8. def get(self, request, username):
  9. try:
  10. # 1、统计用户数量
  11. count = User.objects.filter(
  12. username=username
  13. ).count()
  14. except Exception as e:
  15. print(e)
  16. # 写日志
  17. logger.error(e)
  18. # 2、构建响应返回
  19. return JsonResponse({
  20. 'code': 0,
  21. 'errmsg': 'ok',
  22. 'count': count
  23. })
  1. from django.urls import path, re_path
  2. from users.views import *
  3. urlpatterns = [
  4. re_path(r'^usernames/(?P<username>[a-zA-Z0-9_-]{5,20})/count/$', UsernameCountView.as_view()),
  5. re_path(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', MobileCountView.as_view()),
  6. ]
  1. # 保存后端API服务器地址,视情况而定
  2. var host = 'http://127.0.0.1:8000';
  1. http://IP:8000/usernames/用户名/count/

三、手机号验证接口

  1. class MobileCountView(View):
  2. def get(self, request, mobile):
  3. try:
  4. count = User.objects.filter(
  5. mobile=mobile
  6. ).count()
  7. except Exception as e:
  8. print(e)
  9. logger.error(e)
  10. return JsonResponse({
  11. 'code': 0,
  12. 'errmsg': 'ok',
  13. 'count': count
  14. })
  1. re_path(r'^mobiles/(?P<mobile>1[3-9]\d{9})/count/$', MobileCountView.as_view()),
  1. http://IP:8000/mobiles/手机号/count/

四、解决跨域问题

  1. # 1.安装
  2. pip install django-cors-headers
  3. # 2.INSTALLED_APPS注册
  4. 'corsheaders',
  5. # 3.添加MIDDLEWARE
  6. 'corsheaders.middleware.CorsMiddleware',
  7. # 4.setting.py新增
  8. CORS_ORIGIN_WHITELIST = [
  9. 'http://127.0.0.1',
  10. 'http://127.0.0.1:80',
  11. ]
  12. # 允许在不同主机之间传递cookie数据
  13. CORS_ALLOW_CREDENTIALS = True

五、图形验证码

  1. # 1.新建app verifications
  2. # 2.安装pillow pip install pillow
  3. # 3.项目目录下创建lib的python包导入文件
  4. # 4.配置Redis缓存
  5. "verify_code": {
  6. "BACKEND": "django_redis.cache.RedisCache",
  7. "LOCATION": "redis://82.156.189.83:6379/2",
  8. "OPTIONS": {
  9. "CLIENT_CLASS": "django_redis.client.DefaultClient",
  10. }
  11. },
  12. "sms_code": {
  13. "BACKEND": "django_redis.cache.RedisCache",
  14. "LOCATION": "redis://82.156.189.83:6379/3",
  15. "OPTIONS": {
  16. "CLIENT_CLASS": "django_redis.client.DefaultClient",
  17. }
  18. },
  19. # 5.
  1. from django.views import View # 从django.views导入View
  2. from libs.captcha.captcha import captcha # 导入第三方包captcha
  3. from django_redis import get_redis_connection # 导入redis库
  4. from django.http import HttpResponse # 导入HttpResponse给前端进行响应
  5. import logging # 导入日记模块
  6. logger = logging.getLogger('django')
  7. # 图形验证码接口
  8. class ImageCodeView(View):
  9. def get(self, request, uuid):
  10. # 1、调用库生成图形验证码
  11. text, image = captcha.generate_captcha()
  12. # 2、存储redis
  13. conn = get_redis_connection('verify_code')
  14. try:
  15. # 验证码写入redis
  16. conn.setex(
  17. "img_%s" % uuid,
  18. 300,
  19. text
  20. )
  21. except Exception as e:
  22. print(e)
  23. logger.error(e)
  24. # 3、构建响应
  25. return HttpResponse(image, content_type='image/jpg')
  1. from django.urls import re_path # 从django.urls导入re_path
  2. from . import views # 从当前文件夹,导入views
  3. urlpatterns = [
  4. # 图形验证码
  5. re_path(r'^image_codes/(?P<uuid>[\w-]+)/$', views.ImageCodeView.as_view()),
  6. ]

六、短信验证码

  1. # 1.
  2. # ACCOUNT SID
  3. _accountSid = ''
  4. # AUTH TOKEN
  5. _accountToken = ''
  6. # AppID
  7. _appId = ''
  8. # 2.
  9. if __name__ == '__main__':
  10. # 注意: 测试的短信模板编号为1
  11. CCP().send_template_sms('测试手机号', ['1234', 5], 1)
  12. # 3.
  1. from django.http import HttpResponse,JsonResponse
  2. from aerf_mall.libs.yuntongxun.ccp_sms import CCP
  3. import random
  4. import re
  5. class SMSCodeView(View):
  6. def get(self, request, mobile):
  7. # 1、提取参数
  8. image_code = request.GET.get('image_code')
  9. uuid = request.GET.get('image_code_id')
  10. # 2、校验参数
  11. if not all([image_code, uuid]):
  12. return JsonResponse({
  13. 'code': 400,
  14. 'errmsg': '缺少必要参数'
  15. }, status=400)
  16. if not re.match(r'^\w{4}$', image_code):
  17. return JsonResponse({
  18. 'code': 400,
  19. 'errmsg': '图片验证码格式不符'
  20. }, status=400)
  21. if not re.match(r'^[0-9a-f]{8}(-[0-9a-f]{4}){3}-[0-9a-f]{12}$', uuid):
  22. return JsonResponse({
  23. 'code': 400,
  24. 'errmsg': 'uuid格式不符'
  25. }, status=400)
  26. # 3、校验redis中的图片验证码是否一致——业务层面上的校验
  27. conn = get_redis_connection('verify_code')
  28. # 3.1 提取redis中存储的图片验证码
  29. # get(): b"YBCF"
  30. image_code_from_redis = conn.get("img_%s"%uuid)
  31. # 如果从redis中读出的验证码是空;
  32. if not image_code_from_redis:
  33. return JsonResponse({'code':400, 'errmsg': '验证码过期'}, status=400)
  34. # 如果读出来的不是空,我们要删除该验证码
  35. image_code_from_redis = image_code_from_redis.decode()
  36. conn.delete("img_%s"%uuid)
  37. # 3.2 比对(忽略大小写)
  38. if image_code.lower() != image_code_from_redis.lower():
  39. return JsonResponse({
  40. 'code': 400,
  41. 'errmsg': '图形验证码输入错误'
  42. }, status=400)
  43. # 4、发送短信验证码
  44. conn = get_redis_connection('sms_code')
  45. # 判断60秒之内,是否发送过短信——判断标志信息是否存在
  46. flag = conn.get('flag_%s'%mobile)
  47. if flag:
  48. return JsonResponse({'code':400, 'errmsg':'请勿重复发送短信'}, status=400)
  49. # 构建6位手机验证码
  50. sms_code = "%06d"%random.randint(0, 999999)
  51. print("手机验证码:", sms_code)
  52. # 生成一个redis的pipeline对象
  53. p = conn.pipeline()
  54. # 把验证码存入redis
  55. p.setex(
  56. "sms_%s"%mobile,
  57. 300,
  58. sms_code
  59. )
  60. # 一旦用户发送了短信,需要在redis中存储一个标志
  61. p.setex(
  62. "flag_%s"%mobile,
  63. 60,
  64. '1'
  65. )
  66. p.execute() # 批量执行队列中的指令
  67. # 发送验证码
  68. # 同步调用——只有当该发送短信当函数执行完毕,且返回了;代码才会继续往后执行!
  69. # 如果网络出现了问题,该函数就会一致阻塞在此,导致我们的视图函数无法即使响应!
  70. CCP().send_template_sms(mobile, [sms_code, 5], 1)
  71. return JsonResponse({
  72. 'code': 0,
  73. 'errmsg': 'ok'
  74. })
  1. from django.urls import re_path
  2. from . import views
  3. urlpatterns = [
  4. re_path(r'^sms_codes/(?P<mobile>1[3-9]\d{9})/$', views.SMSCodeView.as_view()),
  5. ]

七、异步方案Celery

  1. # 1.安装Celery
  2. pip install -U Celery
  3. # 2.项目目录下创建celery_tasks的python包
  4. # 3.在celery_tasks下创建config.py和main.py文件
  5. # 4.config.py
  6. # 如果使用 redis 作为中间人
  7. # 需要这样配置:
  8. # 1、将来生产者会把任务发不到redis的10号库
  9. # 2、消费者会从redis的10号库中提取任务并执行
  10. broker_url='redis://127.0.0.1:6379/10'
  11. # 5.main.py
  12. """该文件作为异步应用程序初始化的模块"""
  13. # 在异步任务程序中加载django的环境
  14. import os
  15. os.environ.setdefault(
  16. 'DJANGO_SETTINGS_MODULE',
  17. 'aerf_test.settings.dev' # 此行aerf_test要改成你对应的项目名字
  18. )
  19. from celery import Celery
  20. # 初始化一个应用程序对象(名称可以任意填写)
  21. app = Celery("aerf")
  22. # 加载配置文件——参数是配置文件(模块)的导包路径
  23. # 我们将来是在celery_tasks包所在的目录为工作目录运行异步程序;
  24. app.config_from_object('celery_tasks.config')
  25. # 告知app监听的任务有哪些
  26. # 该函数的参数是一个列表,列表里写的是任务包的导包路径
  27. app.autodiscover_tasks([
  28. 'celery_tasks.sms',
  29. ])
  30. # 6.在celery_tasks下创建sms的python包
  31. # 7.将云通讯目录拷贝到celery_tasks下
  32. # 8.在sms下创建tasks.py文件
  33. """tasks.py文件名是固定,该文件中定义异步任务函数!!"""
  34. from celery_tasks.main import app
  35. from celery_tasks.yuntongxun.ccp_sms import CCP
  36. # 定义一个发送短信的任务函数
  37. # name自定义任务函数名称
  38. # 被app.task装饰的函数就是异步任务函数
  39. @app.task(name='ccp_send_sms_code')
  40. def ccp_send_sms_code(mobile, sms_code):
  41. return CCP().send_template_sms(mobile, [sms_code, 5], 1)
  42. # 9.修改View的视图
  43. from celery_tasks.sms.tasks import ccp_send_sms_code
  44. ccp_send_sms_code.delay(mobile, sms_code)
  45. # 10.启用celery服务
  46. celery -A celery_tasks.main worker -l info
  47. celery -A celery_tasks.main worker -l info -c 10

八、用户注册

  1. from django_redis import get_redis_connection
  2. from django.contrib.auth import login
  3. import json
  4. import re
  5. class RegisterView(View):
  6. def post(self, request):
  7. # 1、提取参数
  8. # request.body --> b'{"username": "xxxx"}'
  9. # request.body.decode() --> '{"username": "xxxx"}'
  10. data = json.loads(request.body.decode())
  11. username = data.get('username')
  12. password = data.get('password')
  13. password2 = data.get('password2')
  14. mobile = data.get('mobile')
  15. sms_code = data.get('sms_code')
  16. allow = data.get('allow')
  17. # 2、校验参数
  18. if not all([username, password, password2, mobile, sms_code]):
  19. return JsonResponse({'code':400, 'errmsg': '缺少参数'}, status=400)
  20. if not re.match(r'^\w{5,20}$', username):
  21. return JsonResponse({'code':400, 'errmsg': '用户名格式有误'}, status=400)
  22. if not re.match(r'^\w{8,20}$', password):
  23. return JsonResponse({'code':400, 'errmsg': '密码格式有误'}, status=400)
  24. if password != password2:
  25. return JsonResponse({'code':400, 'errmsg': '密码输入不一致!'}, status=400)
  26. if not re.match(r'^\d{6}$', sms_code):
  27. return JsonResponse({'code': 400, 'errmsg': '验证码格式有误'}, status=400)
  28. if not allow:
  29. return JsonResponse({'code': 400, 'errmsg': '请求统一用户协议!'}, status=400)
  30. # 手机验证码校验
  31. conn = get_redis_connection('sms_code')
  32. sms_code_from_redis = conn.get('sms_%s'%mobile)
  33. if not sms_code_from_redis:
  34. return JsonResponse({'code': 400, 'errmsg': '短信验证码过期!'}, status=400)
  35. sms_code_from_redis = sms_code_from_redis.decode()
  36. if sms_code_from_redis != sms_code:
  37. return JsonResponse({'code':400, 'errmsg': '短信验证码有误!'}, status=400)
  38. # 3、新建数据,构建用户模型类对象保存数据库
  39. # User.objects.create() --> 构建的用户模型类对象,密码不会加密
  40. # User.objects.create_user() --> 构建用户模型类对象,把明文密码加密
  41. # User.objects.create_superuser() --> 构建用户模型类对象,把明文密码加密以及is_staff=True
  42. try:
  43. user = User.objects.create_user(
  44. username=username,
  45. password=password,
  46. mobile=mobile
  47. )
  48. except Exception as e:
  49. print(e)
  50. # 传入request对象和user对象,把用户信息写入session缓存(redis)中,并且把sessionid返回给浏览器
  51. # 存入cookie
  52. login(request, user)
  53. # 4、构建响应
  54. response = JsonResponse({'code': 0, 'errmsg':' ok'})
  55. response.set_cookie(
  56. 'username',
  57. username,
  58. max_age=3600*24*14
  59. )
  60. return response
  1. re_path(r'^register/$', RegisterView.as_view()),