一、RESTful设计风格
基础概念
全称:Representational State Transfer
1.资源
网络上的一个实体,每个资源都有一个独一无二的URL与之对应;获取资源-直接访问URL即可
2.表现层
3.状态转化
访问一个URL即发生一次客户端和服务端得交互;此次交互将会涉及到数据和状态得变化
客户端需要通过某些方式接触具体得变化 如GET、POST、PUT、PATCH、DELETE
设计原则
2.域名
https://api.example.com/v1 或 https://example.org/api/.
3.版本
4.路径
5.HTTP动词语义
GET、POST、PUT、PATCH、DELETE
7.状态码
1)用HTTP响应码表达
{’code‘:’00000′,’msg‘:’success‘,’data‘:{}}
二、用户系统 – ORM
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("登录成功")
五、用户系统-jwt
1.回顾-会话状态的保持
将会话数据存储到浏览器上独立空间,浏览器每次给网站发请求时,如果检测出当前在cookie区域里有站点的数据,就会自动提交到服务器上。
将会话数据存在服务器上(Django存在数据库中),需要借助cookies,通过sessionId检测
2.jwt前传-base64
防君子不防小人
3.jwt前传-HMAC-SH256
import hmac
h = hmac.new(key,str,digestmod='SHA256')
h.digest()
4.JWT-json–web–token
JWT-三大组成
格式:
{‘alg’:’HS256′,’typ’:’JWT’}
2)签名校验-根据传过来的header和payload按alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
6.Pyjwt
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")
5.用户系统-修改个人信息
6.装饰器校验jwt
django 提供了一个装饰器 method_decorator,可以将函数的装饰器转换成方法装饰器
写一个校验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
7.短信接入
1.浏览器点击发送验证码->后端生成随机码并保存在redis(数据在规定时间内有效)
后端必须知道验证码是多少
第三方短信平台
发短信业务–需要接入其他平台【第三方平台】,让短信平台帮助我们发送短信,该服务通过是有偿服务
容联+云通讯 https://yuntongxun.com
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)
验证码功能流程
2.后端接到请求后
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')
8.celery
broker – 消息传输的中间件,生产者一旦有消息发送,将发至broker broker可以用【RQ,redis】
blackend – 用于存储消息/任务结果,如果需要跟踪和查询任务状态,则需添加要配置相关
worker – 工作者 – 消费/执行broker中消息/任务的进程
使用 – 创建woker(不使用django)
from celery import Celery
app = Celery('guoxiaonao',
broker='redis://172.3.3.100:6379/5'
)
# 创建任务函数
@app.task
def task_test():
print('task is run ... ')
使用 – 启动woker
使用 – 创建生产者 – 推送任务
在tasks.py 文件的同级目录下进入ipython3执行
task_test.delay()
celery -A 项目同名目录名 worker -l info
六、文章系统
模型类
列表页 – 处理
方式2:后端从数据库里获取全部文章内容,截取好后,响应给前端
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
文章缓存
典型读多写少
有点:
缺点:
有点:灵活、存储成本最有
装饰器缓存
判断是否在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 |
无 |
无 |
|
varchar(50) |
留言内容 |
无 |
无 |
|
created_time |
无 |
无 |
||
int |
int |
无 |
||
varchar(10) |
留言的发布者 |
无 |
||
topic_id |
varchar(10) |
文章 |
无 |
#关联留言和回复
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']]
原文地址:https://blog.csdn.net/m0_43448734/article/details/132606203
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.7code.cn/show_12327.html
如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱:suwngjj01@126.com进行投诉反馈,一经查实,立即删除!