全称:Representational State Transfer
1.资源
网络上的一个实体,每个资源都有一个独一无二的URL与之对应;获取资源-直接访问URL即可
2.表现层
资源的表现形式 如HTML、xml、JPG、json等
3.状态转化
访问一个URL即发生一次客户端和服务端得交互;此次交互将会涉及到数据和状态得变化
客户端需要通过某些方式接触具体得变化 如GET、POST、PUT、PATCH、DELETE
1.协议 - http/https
2.域名
域名中体现出api字样
https://api.example.com/v1 或 https://example.org/api/.
3.版本
https://api.example.com/v1
4.路径
路径中避免使用动词,资源用名词表示
5.HTTP动词语义
GET、POST、PUT、PATCH、DELETE
示例

6.巧用查询字符串

7.状态码
1)用HTTP响应码表达

2)自定义内部code进行响应
{’code‘:'00000','msg':'success','data':{}}
model
- class UserProfile(models.Model):
-
- username=models.BigAutoField(verbose_name="用户名",primary_key=True)
- nickname=models.CharField(max_length=20,verbose_name="昵称")
- password=models.CharField(max_length=32)
- email = models.EmailField()
- phone=models.CharField(max_length=11)
- avatar=models.ImageField(upload_to='avatar',null=True)
- sign=models.CharField(max_length=50,verbose_name="个人签名",default=default_sign)
- info=models.CharField(max_length=150,verbose_name="个人简介",default='')
- created_time=models.DateTimeField(auto_now_add=True)
- updated_time=models.DateTimeField(auto_now=True)
-
- class Meta:
- db_table = 'user_user_profile'
只处理后端
- from models import UserProfile
- import hashlib
- # 数据校验 前后端都要做
- class UserViews(APIView):
-
- def post(self,request):
- username = request.data['user']
- nickname = request.data['nick']
- email = request.data['email']
- password_1 = request.data['password_1']
- password_2 = request.data['password_2']
- phone = request.data['phone']
-
- # 参数基本检查
- if password_1 != password_2:
- return Response("密码不一致")
- # 用户名可不可用
- old_users = UserProfile.objects.filter(username=username)
- if old_users:
- return Response("用户名已被使用")
- # 插入数据(MD5)
- p_m = hashlib.md5()
- p_m.update(password_1.encode())
-
- UserProfile.objects.create(username=username,nickname=username,password=p_m.hexdigest(),email=email,phone=phone)
-
- return Response("注册成功")
views
- class LoginViews(APIView):
-
- def post(self,request):
- username = request.data['user']
- password = request.data['psd']
-
- user_info = UserProfile.objects.filter(username=username)
- if not user_info:
- return Response("用户不存在")
-
- p_m = hashlib.md5()
- p_m.update(password.encode())
- if p_m.hexdigest() != user_info.first().password:
- return Response("密码不正确")
- return Response("登录成功")
cookies
将会话数据存储到浏览器上独立空间,浏览器每次给网站发请求时,如果检测出当前在cookie区域里有站点的数据,就会自动提交到服务器上。
session
将会话数据存在服务器上(Django存在数据库中),需要借助cookies,通过sessionId检测
防君子不防小人

第一个参数 加密的key,bytes类型
第二个参数 欲加密的串,bytes类型
第三个参数 hmac的算法,指定为SHA256
- import hmac
- h = hmac.new(key,str,digestmod='SHA256')
- h.digest()
header
格式:
alg代表要使用的算法
typ表明token的类别 - 必须大写JWT
{'alg':'HS256','typ':'JWT'}
payload 分为公有声明和私有声明
公有声明:提供内置关键字用于描述常见的问题,均可选

私有声明:可添加自定义的key 如用户名
![]()
signature 根据header中的alg确定具体算法
5.JWT-校验jwt规则
1)解析header,确认alg
2)签名校验-根据传过来的header和payload按alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
3)获取payload自定义内容
6.Pyjwt
安装pyjwt(pip3 install)
encode(payload,key,algorithm)
payload:这里是字典,需添加公有声明和私有声明
key:自定义的加密key
algorithm:需要使用的加密算法
decode(token,key)
token:上面生成的token
key:自定义的加密key
- import jwt,time
- def makeToken(username,expTime=3600*24):
- timeTime = time.time()
- key = '123456'
- payload = {"username":username,"exp":timeTime+expTime}
- return jwt.encode(payload,key,algorithm="HS256")
django 提供了一个装饰器 method_decorator,可以将函数的装饰器转换成方法装饰器
from django.utils.decorators import method_decorator
@method_decorator(logging_check)
写一个校验token,传递用户的装饰器,写完后只需在函数前加上述@操作
- from django.http import JsonResponse
- import jwt
- from mydemo import settings
- from myapp.models import UserProfile
- def logging_check(func):
- def wrap(request,*args,**kwargs):
- # 获取token
- token = request.META.get('HTTP_AUTHOPIZAION')
- if not token:
- return JsonResponse({'code':403,'error':"Please login again"})
- # 校验token
- # 校验jwt
- try:
- res = jwt.decode(token,settings.JWT_TOKEN_KEY)
- except Exception as e:
- return JsonResponse({'code':403,'error':'Please again'})
-
- # 获取登录用户
- username = res['username']
- user = UserProfile.objects.get(username=username)
- request.myuser = user # 将user传给下面的request
-
- return func(request,*args,**kwargs)
- return wrap
1.浏览器点击发送验证码->后端生成随机码并保存在redis(数据在规定时间内有效)
2.注册创建->后端获取前端输入的验证码
3.两个短信验证码进行比较
后端必须知道验证码是多少
发短信业务-需要接入其他平台【第三方平台】,让短信平台帮助我们发送短信,该服务通过是有偿服务
容联+云通讯 https://yuntongxun.com
案例
xxxx1是1 xxxx2是2 xxxx3是3

-
- import datetime
- import hashlib
- import base64
- import requests # 发http/https请求
- import json
-
- class YunTongXin():
-
- base_ul = 'https://app.cloopen.com:8883'
-
- def __init__(self,accountSid,accountToken,appId,templateId):
- self.accountSid = accountSid
- self.accountToken = accountToken
- self.appId = appId # 应用id 写死
- self.templateId = templateId # 模板id 写死
-
- def get_request_url(self,sig):
- self.url = self.base_ul + '/2013-12-26/Accounts/%s/SMS/TemplateSMS?sig=%s'%(self.accountSid,sig)
- return self.url
-
- def get_timestamp(self):
- # 生成时间戳
- return datetime.datetime.now().strftime('%Y%m%d%H%M%S')
-
- def get_sig(self,timestamp):
- # 生成业务url中的sig
- s = self.accountSid+self.accountToken+timestamp
- m = hashlib.md5()
- m.update(s.encode())
- return m.hexdigest().upper()
-
- def get_request_header(self,timestamp):
- # 生成请求头
- s = self.accountSid+':'+timestamp
- auth = base64.b64encode(s.encode()).decode()
- return {
- 'Accept':'application/json',
- 'Content-Type':'application/json;charset=utf-8',
- 'Authorization':auth
- }
-
- def get_request_body(self,phone,code):
- # 生成请求体
- return {
- "to":phone,
- "appId":self.appId,
- "templateId":self.templateId,
- "datas":[code,"3"]
- }
-
- def get_request_api(self,url,header,body):
- res = requests.post(url,headers=header,data=body) #res是一个对象
- return res.text # 响应体的内容
-
- def run(self,phone,code):
- # 获取时间
- timestamp = self.get_timestamp()
- sig = self.get_sig(timestamp)
- url = self.get_request_url(sig)
- header = self.get_request_header(timestamp)
- # print(url)
- # 生成请求体
- body = self.get_request_body(phone,code)
- # 发请求
- data = self.get_request_api(url,header,json.dumps(body))
- return data
-
- if __name__ == '__main__':
-
- yun = YunTongXin('xxxx1','xxxx2','xxxx3',1)
- res = yun.run('注册手机',"2341")
- print(res)
1.前端点击 获取验证码 发送请求到后端
2.后端接到请求后
1.生成随机验证码
2.存储验证码->redis
3.发送验证码
3.注册时,需要提交验证码,并在注册逻辑中对比验证码是否正确
生成4位随机数
random_number = random.randint(0,9999)
four_digit_number = '{:04d}'.format(random_number)
- import random
- import redis
- from tools.sms import YunTongXin
- class Sms(APIView):
-
- def post(self,request):
- phone = request.data['phone']
- random_number = random.randint(0,9999)
- four_digit_number = '{:04d}'.format(random_number)
-
- conn = redis.Redis(connection_pool=redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=1000,decode_responses=True,db=15))
- conn.setex(phone,60,four_digit_number)
- yun = YunTongXin('xxxx1','xxxx2','xxxx3',1)
-
- res = yun.run(phone,four_digit_number)
- if res['statusCode'] == '000000':
- return Response('ok')
- else:
- return Response('false')
- class SmsCheck(APIView):
- def post(self,request):
- phone = request.data['phone']
- code = request.data['code']
-
- conn = redis.Redis(connection_pool=redis.ConnectionPool(host='127.0.0.1', port=6379,max_connections=1000,decode_responses=True,db=15))
- redis_code = conn.get(phone)
- if not redis_code:
- return Response('code 过期')
- if redis_code != code:
- return Response('验证码错误')
- return Response('ok')
broker - 消息传输的中间件,生产者一旦有消息发送,将发至broker broker可以用【RQ,redis】
blackend - 用于存储消息/任务结果,如果需要跟踪和查询任务状态,则需添加要配置相关
worker - 工作者 - 消费/执行broker中消息/任务的进程

能不能celery的标准
1.有没有阻塞
2.实时反馈的不行
- from celery import Celery
- app = Celery('guoxiaonao',
- broker='redis://172.3.3.100:6379/5'
- )
-
- # 创建任务函数
- @app.task
- def task_test():
- print('task is run ... ')
在tasks.py文件同级目录下执行
celery -A tasks worker --loglevel=info
在tasks.py 文件的同级目录下进入ipython3执行
from tasks import task_test
task_test.delay()
使用 - 存储执行结果 - work
要想存储执行结果需要添加 backend
django中使用celery
1.创建celery配置文件
项目同名目录下创建celery.py
2.应用下创建tasks.py集中定义队形worker函数
3.视图函数充当生产者,推送具体worker函数
4.项目目录下启动worker
celery -A 项目同名目录名 worker -l info
列表页 - 处理
方式1:后端给前端,文章全部内容 前端自己截取
方式2:后端从数据库里获取全部文章内容,截取好后,响应给前端
方式3:数据库冗余一个字段【简介】,后端只去简介字段内容
model 模型类
- from django.db import models
- # Create your models here.
- class Topic(models.Model):
- title = models.CharField(max_length=50,verbose_name="文章标题")
- category = models.CharField(max_length=20,verbose_name="文章分类")
- limit = models.CharField(max_length=20,verbose_name="文章权限")
- introduce = models.CharField(max_length=90,verbose_name="文章简介")
- content = models.TextField(verbose_name="文章内容")
- created_time = models.DateTimeField(auto_now_add=True)
- updated_time = models.DateTimeField(auto_now=True)
就是获取前端数据,将数据存入数据库 无技术可言
游客访问只能看到公共的文章,博主自己能访问自己的私有文章
在列表页点击文章标题进入文章详情页面
获取用户文章的上一篇
当前文章id 1
select * from 表 where id > 1 and people = gxn order by id asc limit 1
下一篇
当前文章id 4
select * from 表 id < 4 and people = gxn order by id desc limit 1
典型读多写少
缓存方案一:cache_page(过期时间s)
有点:
缺点:
1.无法按照具体的方可身份,进行针对性的存储,
例如:存储的是博主访问自身博客的数据,方可到访是可能会读到 博主删除的缓存
2.删除缓存成本太高【出现新旧数据不一致】
缓存方案二:局部 - cache.set/get
有点:灵活、存储成本最有
缺点:代码实现成本高
装饰器缓存
判断是否在redis中缓存 如果有直接retrun 没有执行视图然后存储缓存
res = fun(request,*args,**kwargs) 去执行视图函数的内容
- from django.http import HttpResponse
- def cache_set(expire):
-
- def _cache_set(fun):
-
- def wrapper(request,*args,**kwargs):
- print(args[0])
- print(args[0].path_info)
- print(args[0].user)
- aa = kwargs['pk']
- if aa == 111:
- # 如果aa == 111 执行视图
- res = fun(request,*args,**kwargs)
- return res
- else:
- return HttpResponse(aa)
- return wrapper
-
- return _cache_set
采用创建父项id的方式实现
| 字段名 | 类型 | 作用 | 备注1 | 备注2 |
| id | int | 主键自增 | 无 | 无 |
| content | varchar(50) | 留言内容 | 无 | 无 |
| created_time | date | 留言创建时间 | 无 | 无 |
| parent_message | int | 该留言的父留言,此ID若存在证明该留言为回复 | int | 无 |
| publisher_id | varchar(10) | 留言的发布者 | user_profile外键 | 无 |
| topic_id | varchar(10) | 文章 | topic 外键 | 无 |
- #关联留言和回复
- all_messages = Message.objects.filter(topic=author_topic).order_by('-created_time')
-
- msg_list = []
- rep_dic = {}
- m_count = 0
- for msg in all_messages:
- if msg.parent_message:
- #回复
- rep_dic.setdefault(msg.parent_message, [])
- rep_dic[msg.parent_message].append({'msg_id':msg.id,'publisher':msg.publisher.nickname, 'publisher_avatr':str(msg.publisher.avatar),'content':msg.content, 'created_time':msg.created_time.strftime('%Y-%m-%d %H:%M:%S')})
- else:
- #留言
- m_count += 1
- msg_list.append({'id':msg.id, 'content':msg.content,'publisher':msg.publisher.nickname, 'publisher_avatar':str(msg.publisher.avatar),'created_time':msg.created_time.strftime('%Y-%m-%d %H:%M:%S'), 'reply':[]})
-
- for m in msg_list:
- if m['id'] in rep_dic:
- m['reply'] = rep_dic[m['id']]