django缓存和跨域解决和短信验证码的使用

缓存

  在实际项目中,存在大量的数据检索,比如我们刷微博的时候,刚开始加载速度慢一点,然后第一次加载完毕之后,如果你此时的手机没有网络,但是你发现你的微博还是可以照样刷,但是刷到一定的页面就走不动了,那么为什么你在刚开始没有网络的时候还可以接着刷呢?这就是用到了缓存,在你第一次加载的时候,就去数据库中将数据查出来,然后直接缓存到你的移动端,那么我们现在要做的就是将数据从数据库中查出来,然后缓存到内存中,下次来请求的时候,直接去缓存中获取,就不用走数据库了,缓解我的数据库的压力,具体书写如下

views中的书写

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from rest_framework.exceptions import AuthenticationFailed
from rest_framework.response import Response
from app01 import models
from app01 import seria
from app01 import auth
from django.views.decorators.cache import cache_page
import uuid
from django.core.cache import cache
import time


# Create your views here.


class Author(APIView):
    # 只有认证了才可以看
    # authentication_classes = []
    # permission_classes = []
    # throttle_classes = []

    # 返回了所有的图书

    def get(self, request):
        author_list = models.User.objects.all()
        # 进行序列化
        user_ser = seria.UserSerializer(instance=author_list, many=True)
        return Response(user_ser.data)


class Login(APIView):
    authentication_classes = []
    permission_classes = []
    throttle_classes = []
    def post(self, request):
        back_dic = {'code': 100, 'msg': ''}
        username = request.data.get('username')
        password = request.data.get('password')
        user_type = request.data.get('user_type')
        try:
            user_obj = models.User.objects.filter(name=username, pwd=password, user_type=user_type).get()
            token = uuid.uuid4()
            # 添加到了数据库
            models.Token.objects.update_or_create(user=user_obj, defaults={'token': token})
            # 添加到缓存
            back_dic['msg'] = '登录成功'
            back_dic['token'] = token
            cache.set(token, user_obj.pk, 300)
            # print(cache.get(token))

        except AuthenticationFailed as e:
            back_dic['code'] = 101
            back_dic['msg'] = '用户名或者密码错误'
        except Exception as e:
            back_dic['code'] = 102
            back_dic['msg'] = '未知错误'
        return Response(back_dic)


# 测试


def test(request):
    print(1111)
    return HttpResponse('test ok')

@cache_page(5)
def index(request):
    ctime = time.time()
    author_list = models.User.objects.all()
    return render(request, 'index.html', locals())
Views

写完之后,我们需要在认证中添加和认证

from rest_framework.authentication import BaseAuthentication
from rest_framework.permissions import BasePermission
from rest_framework.throttling import SimpleRateThrottle
from app01 import models
from django.core.cache import cache
from rest_framework.exceptions import AuthenticationFailed


class Authentications(BaseAuthentication):
    def authenticate(self, request):
        # print(request.META)
        token = request.META.get('HTTP_TOKEN')
        # 能取到说明是通过了
        user_pk = cache.get(token)
        if user_pk:
            user_obj = models.User.objects.filter(pk=user_pk).first()
            # 返回的必须是一个元组
            return user_obj, token
        token_obj = models.Token.objects.filter(token=token).first()
        # 说明是一个用户
        if token_obj:
            cache.set(token, token_obj.pk, 300)
            return token_obj.user, token_obj
        else:
            raise AuthenticationFailed('您还没有登录呢!')


class Permissions(BasePermission):

    def has_permission(self, request, view):
        if request.user.user_type == 1:
            return True
        else:
            return False


class Throtters(SimpleRateThrottle):
    scope = 'three'

    def get_cache_key(self, request, view):
        return self.get_ident(request)
认证

模板中实现局部缓存的方式

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcss.com/jquery/3.4.1/jquery.min.js"></script>
    <link href="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/css/bootstrap.min.css" rel="stylesheet">
    <script src="https://cdn.bootcss.com/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
{# 单页面缓存 #}
{# 当有局部缓存的时候,需要将原来的装饰器的缓存注释掉 #}
<p>{{ ctime }}</p>
<ul>
    {% for author in author_list %}
    <li>{{ author.name }}</li>
    {% endfor %}

</ul>
{# 让他变成局部的缓存 #}
{% load cache  %}
{% cache 1 'test' %}
<p>{{ ctime }}</p>
{% endcache %}

{% cache 2 'aaa' %}
<p>{{ ctime }}</p>
{% endcache %}
<button id="btn">提交</button>
</body>
<script>
    $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/test/',
            type:'post',
            data:{'name': 'egon'},
            contentType:'application/json',
            success:function (data) {
                alert(123);
                console.log(data)
            }
        })
    })
</script>
</html>
html展示

模型表的展示

from django.db import models
from django.contrib import auth

# Create your models here.


class User(models.Model):
    name = models.CharField(max_length=32)
    pwd = models.CharField(max_length=64)
    user_type = models.IntegerField(choices=((1, '超级管理员'), (2, '普通管理员'), (3, '普通用户')), default=3)


class Token(models.Model):
    user = models.OneToOneField(to='User')
    token = models.CharField(max_length=64)
models

在settings中做一些缓存的配置

MIDDLEWARE = [
    # 'app01.middlewares.MiddleToken',
    # 'django.middleware.cache.UpdateCacheMiddleware',  # 重写了process_response的方法
    'django.middleware.security.SecurityMiddleware',
    'django.contrib.sessions.middleware.SessionMiddleware',
    'django.middleware.common.CommonMiddleware',
    'django.middleware.csrf.CsrfViewMiddleware',
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    'django.contrib.messages.middleware.MessageMiddleware',
    'django.middleware.clickjacking.XFrameOptionsMiddleware',
    # 'django.middleware.cache.FetchFromCacheMiddleware'  # 重写了process_request的方法
]
# 全站的只是配置了存的方式,但是没有时间的限制,所以要配置超时时间 如果单页面配置了那就以单页面为准
# CACHE_MIDDLEWARE_SECONDS = 10

# 配置缓存 文件存储的形式
CACHES = {
 'default': {
  'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',  # 指定缓存使用的引擎
  'LOCATION': 'D:\mcc\cache',          # 指定缓存的路径
  'TIMEOUT': 300,              # 缓存超时时间(默认为300秒,None表示永不过期)
  'OPTIONS': {
   'MAX_ENTRIES': 300,            # 最大缓存记录的数量(默认300)
   'CULL_FREQUENCY': 3,           # 缓存到达最大个数之后,剔除缓存个数的比例,即:1/CULL_FREQUENCY(默认3)
  }
 }
}
View Code

然后就可以简单的实现缓存了,但是实际中,我们缓存也是有一个数据库的,我们一般都使用的是redis数据库,这个详细请看上一篇博客,具体项目中运用,我这里使用的是采用短信验证码登录之后将数据放到缓存中

class SMSAPIView(APIView):
    '''
    1.用户不能连续发多次的短信,得有一个频率的校验-为钱为防爬
    '''
    throttle_classes = [SMSSimpleRateThrottle]
    def get(self, request, *args, **kwargs):
        mobile = request.query_params.get('mobile')
        # 字段必须的
        if not mobile:
            return Response({
                'status': 2,
                'msg': 'mobile参数是必须的'
            })
        # 后台要多mobile数据进行安全校验
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return Response({
                'status': 2,
                'msg': '手机号有误'
            })
        # # 生成随机的验证码
        code = ''
        for i in range(6):
            code += str(random.randint(0, 9))
        # redis 存储
        cache.set(mobile, code, constat.SMS_EXPIRE_TIME)
        # 调用短信第三方发送短信
        result = send_sms('176****8046', (code, constat.SMS_EXPIRE_TIME), 1)
        if not result:
            return Response({
                'status': 1,
                'result': '短信发送失败'
            })
        return Response({
            'status': 0,
            'result': '短信发送成功'
        })
View Code

获取的时候可以直接get就好。

跨域问题

什么是跨域? HTTP,域名,端口有一个不同就是跨域,是因为浏览器的同源策略导致这种问题的出现

解决方式一

新建一个django项目,用当前项目的ajax向新项目发送请求

<script>
    $('#btn').click(function () {
        $.ajax({
            url:'http://127.0.0.1:8001/test/',
            type:'post',
            data:{'name': 'egon'},
            contentType:'application/json',
            success:function (data) {
                alert(123);
                console.log(data)
            }
        })
    })
</script>
View Code

测试的视图函数

def test(request):
    # print('1111')
    # print(request.META.get('HTTP_ORIGIN'), type(request.META.get('HTTP_ORIGIN')))
    # Access-Control-Allow-Origin
    import json
    # print(111)
    obj = HttpResponse(json.dumps({'name': 'lqz', 'age': 32}))
    # * 就是全部都可以匹配
    # obj['Access-Control-Allow-Origin'] = '*'
    # 单个匹配
    return obj
test

然后,再打印的时候发现我们是收到了这个请求,但是发的时候被浏览器阻拦了,那我们就要再新项目中允许别的地址给我发送请求,那么这个方法就是要在回去的时候允许,回去的时候走的方法是process_response,那我们就重写这个方法

from django.utils.deprecation import MiddlewareMixin


class Middle(MiddlewareMixin):

    def process_response(self, request, response):
        if request.method == 'OPTIONS':
            # Content-Type
            response['Access-Control-Allow-Headers'] = 'Content-Type'
            # obj['Access-Control-Allow-Headers'] = 'Content_Type'
        http = request.META.get('HTTP_ORIGIN')
        num = http.split(':')[-1]
        # print(http)
        #
        if num in ['8000', '8001', '8002', '8003', '8004', '8005']:
            # print(111)
            # print('222', http)
            response['Access-Control-Allow-Origin'] = http
        return response
中间件

这样子就做到了跨域问题的解决

解决方式二

调用别人写好的库,然后只需要配置几个参数就好

下载

pip install django-cors-headers 

settings中配置

app中注册
INSTALLED_APPS=[
'corsheaders',]

# 允许跨域源,但是由于是所有的都允许,后面什么第三方的网站都可以拿到我的数据
# 所以要改成False
CORS_ORIGIN_ALLOW_ALL = False

# 设置白名单允许部分跨域
CORS_ORIGIN_WHITELIST = [
    # 记住是自己的前端,要携带端口
    'http://127.0.0.1:8080',
    # 一般就是浏览器那里显示什么,这里就是什么
    # 'http://localhost:8080'
]

之后我们访问的时候就可以了

短信验证码

我们现在在登录一个网站的时候,大多数人都会采用电话号码登录,然后获得验证码的方式进行使用,我们在项目中也采用了这种方式,然后我使用的是容联云通讯

使用步骤如下

1.直接百度搜索容联云通讯,进行注册

2.注册成功后会给你送免费使用额度

3.查看短信接口

然后我们可以直接去查看短信接口的书写,看完之后如果不懂就看demo,最好的例子

4.下载demo

5.配置修改

将sdk中的两个文件拷贝到我们的项目中,然后修改一些东西,因为这里只支持python2.7,所以要做一些修改

1.导包的地方
from hashlib import md5
import base64
import datetime
from urllib import request as urllib2
import json
from .xmltojson import xmltojson
2.异常捕获的地方
        except Exception as error:
            if self.Iflog:
                self.log(url, body, data)
            return {'172001': '网络错误'}
3.int和str
4.base64
5.端口

具体的我上面没有写完,我只是列出了大概需要改的地方

6.我们使用的时候还要自己新建一个文件,用来重写他的发送短信验证码的方法

from .CCPRestSDK import REST
from django.conf import settings
# 注:在配置文件dev中完成四个配置信息
# 说明:主账号,登陆云通讯网站后,可在"控制台-应用"中看到开发者主账号ACCOUNT SID
_accountSid = settings.SMS_ACCOUNTSID
# 说明:主账号Token,登陆云通讯网站后,可在控制台-应用中看到开发者主账号AUTH TOKEN
_accountToken = settings.SMS_ACCOUNTTOKEN
# 说明:请使用管理控制台首页的APPID或自己创建应用的APPID
_appId = settings.SMS_APPID
# 说明:请求地址,生产环境配置成app.cloopen.com,开发环境配置成sandboxapp.cloopen.com
_serverIP = settings.SMS_SERVERIP

# 说明:请求端口 ,生产环境为8883
_serverPort = "8883"
# 说明:REST API版本号保持不变
_softVersion = '2013-12-26'

def send_sms(mobile, code_expire_tuple, temp_id):
    # 配置
    rest = REST(_serverIP, _serverPort, _softVersion)
    rest.setAccount(_accountSid, _accountToken)
    rest.setAppId(_appId)
    # 发送
    result = rest.sendTemplateSMS(mobile, code_expire_tuple, temp_id)
    # 结果:信息成功发生,结果字典result中 statuCode 字段为 "000000"
    if result.get("statusCode") == "000000":
        return True  # 表示发送短信成功
    else:
        return False  # 表示发送失败
View Code

7.去settings中配置

# # 短信的配置  荣联云通信配置
SMS_ACCOUNTSID = '你的accountsid'
SMS_ACCOUNTTOKEN = '你的token'
SMS_APPID = '如果是测试账号,就是未上线,公司的就是上线'
SMS_SERVERIP = 'sandboxapp.cloopen.com'

8.测试

import os
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'luffyapi.settings.dev')
import django
django.setup()


from luffyapi.libs.yuntongxun import send_sms

import random

def get_code():
    code = ""
    for i in range(6):
        code += str(random.randint(0, 9))
    return code

code = get_code()
print(code)
result = send_sms('你添加的测试手机号', (code, 5), 1)
print(result)

现在就可以正常使用了

短信验证码的频率校验

class SMSAPIView(APIView):
    '''
    1.用户不能连续发多次的短信
    '''
    throttle_classes = [SMSSimpleRateThrottle]
    def get(self, request, *args, **kwargs):
        mobile = request.query_params.get('mobile')
        # 字段必须的
        if not mobile:
            return Response({
                'status': 2,
                'msg': 'mobile参数是必须的'
            })
        # 后台要多mobile数据进行安全校验
        if not re.match(r'^1[3-9]\d{9}$', mobile):
            return Response({
                'status': 2,
                'msg': '手机号有误'
            })
        # # 生成随机的验证码
        code = ''
        for i in range(6):
            code += str(random.randint(0, 9))
        # redis 存储
        cache.set(mobile, code, constat.SMS_EXPIRE_TIME)
        # 调用短信第三方发送短信
        result = send_sms('17621948046', (code, constat.SMS_EXPIRE_TIME), 1)
        if not result:
            return Response({
                'status': 1,
                'result': '短信发送失败'
            })
        return Response({
            'status': 0,
            'result': '短信发送成功'
        })
View Code

短信验证码的登录

class LoginMobileAPIView(APIView):
    def post(self, request, *args, **kwargs):
        mobile = request.data.get('mobile')
        code = request.data.get('code')
        # 从redis中取出我们上面设置的验证码
        old_code = cache.get(mobile)
        if not old_code:
            return Response({
                'msg': '验证码失效'
            })
        if old_code != code:
            return Response({
                'msg': '验证码错误'
            })
        # 校验用户的手机号是否合法
        try:
            user = User.objects.get(mobile=mobile)
            return Response({
                'status': 0,
                'msg': '登录成功',
                'token': get_jwt_token(user),
                'user': UserModelSerializer(user).data
            })
        except:
            return Response({
                'msg': '手机号还没有注册'
            })
View Code

短信验证码的注册

class RegisterMobileAPIView(APIView):
    def post(self, request, *args, **kwargs):
        mobile = request.data.get('mobile')
        password = request.data.get('password')
        code = request.data.get('code')
        old_code = cache.get(mobile)
        if not old_code:
            return Response({
                'msg': '验证码失效'
            })
        if old_code != code:
            return Response({
                'msg': '验证码错误'
            })
        try:
            User.objects.get(mobile=mobile)
            return Response({
                'status': 1,
                'msg': '用户已存在'
            })
        except:
            result = User.objects.create_user(mobile=mobile, password=password, username=mobile)
            if result:
                return Response({
                    'status': 0,
                    'msg': '注册成功'
                })
            else:
                return Response({
                    'status': 1,
                    'msg': '注册失败'
                })
View Code

猜你喜欢

转载自www.cnblogs.com/mcc61/p/11160985.html
今日推荐