本文介绍: 全称:Representational State Transfer1.资源网络上的一个实体,每个资源都有一个独一无二的URL与之对应获取资源-直接访问URL即可2.表现层资源的表现形式 如HTML、xml、JPG、json等3.状态转化访问一个URL即发生一次客户端服务端交互;此次交互将会涉及到数据状态得变化客户端需要通过某些方式接触具体得变化 如GET、POST、PUT、PATCH、DELETE。

一、RESTful设计风格

基础概念

全称: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‘:{}}

二、用户系统 – ORM

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("登录成功")

五、用户系统-jwt

1.回顾-会话状态的保持

cookies

        将会话数据存储浏览器独立空间浏览器每次给网站请求时,如果检测当前cookie区域里有站点数据,就会自动提交服务器上。

session

        将会话数据存在服务器上(Django存在数据库中),需要借助cookies,通过sessionId检测

2.jwt前传-base64

防君子不防小人

3.jwt前传-HMAC-SH256

一个参数 加密keybytes类型

第二个参数 欲加密的串,bytes类型

第三参数 hmac算法指定为SHA256

import hmac
h = hmac.new(key,str,digestmod='SHA256')
h.digest()

 4.JWT-jsonwebtoken

JWT-三大组成

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")

5.用户系统-修改个人信息

6.装饰校验jwt

        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

7.短信接入

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')

8.celery

broker消息传输中间件生产者一旦有消息发送,将发至broker    broker可以用【RQ,redis】

blackend用于存储消息/任务结果,如果需要跟踪和查询任务状态,则需添加配置相关

worker – 工作者 – 消费/执行broker中消息/任务进程 

能不能celery标准

1.有没有阻塞

2.实时反馈的不行

使用创建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文件同级目录执行

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']]

原文地址:https://blog.csdn.net/m0_43448734/article/details/132606203

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。

如若转载,请注明出处:http://www.7code.cn/show_12327.html

如若内容造成侵权/违法违规/事实不符,请联系代码007邮箱suwngjj01@126.com进行投诉反馈,一经查实,立即删除!

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注