luffy项目
2019-03-10 15:26:48 0 举报
AI智能生成
项目
作者其他创作
大纲/内容
课程模块
根据功能设计表结构
接口的编写
Django的MEDIA配置
#settings.py
STATIC_URL = "/static/"
#Media配置
MEDIA_URL = ”media/“
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
STATIC_URL = "/static/"
#Media配置
MEDIA_URL = ”media/“
MEDIA_ROOT = os.path.join(BASE_DIR,"media")
#urls.py
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from new_luffy import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/course/', include("course.urls")),
# media路径配置
url(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})
]
from django.conf.urls import url, include
from django.contrib import admin
from django.views.static import serve
from new_luffy import settings
urlpatterns = [
url(r'^admin/', admin.site.urls),
url(r'^api/course/', include("course.urls")),
# media路径配置
url(r'media/(?P<path>.*)$', serve, {'document_root': settings.MEDIA_ROOT})
]
redis
Redis特点
Redis支持数据的持久化,可以将内存中的数据保存在磁盘中,重启的时候可以再次加载进行使用。
Redis支持五种数据类型。
Redis支持数据库备份。
Redis的优势
Redis性能极高,读的速度是110000次/s,写的速度是81000次/s
Redis丰富的数据类型,String,Lists,Hashes,Sets以及Ordered Sets
Redis的所有操作都是原子性的,意思就是要么成功执行,要么完全失败不执行,多个操作支持事物。即MULTI和EXEC指令包起来。
Redis有丰富的特性,支持publish/subscribe,通知,key过期等等特性。
Redis配置
可以通过redis-cli 进入交互模式,使用config命令查看或设置配置项。也可以进入配置文件用vim编辑器进行修改。
redis数据类型
-- String 字符串
-- redis的string可以包含任何数据,包括图片以及序列化的对象,一个键最大能存储512MB。
-- redis的string可以包含任何数据,包括图片以及序列化的对象,一个键最大能存储512MB。
-- Hash 哈希
-- redis的hash是一个String类型的key和value的映射表,hash特别适合存储对象,类比python字典。
-- redis的hash是一个String类型的key和value的映射表,hash特别适合存储对象,类比python字典。
-- List 列表
-- redis的list是简单的字符串列表,按照插入顺序排序,可以从两端进行添加,类似于双向链表,列表还可以进行阻塞。
-- redis的list是简单的字符串列表,按照插入顺序排序,可以从两端进行添加,类似于双向链表,列表还可以进行阻塞。
-- Set 集合
-- redis的set是字符串类型的无序且不重复集合。集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。
-- redis的set是字符串类型的无序且不重复集合。集合是通过哈希表实现的,所以添加,删除,查找的时间复杂度都是O(1)。
-- Zset 有序集合
-- redis的zset和set一样,不同的是每个元素都会关联一个double类型的分数,redis正是通过对分数的排序对集合进行有序存储。
-- redis的zset和set一样,不同的是每个元素都会关联一个double类型的分数,redis正是通过对分数的排序对集合进行有序存储。
下载
pip install redis
连接
Redis提供两个类Redis和StrictRedis用于实现Redis的命令,StrictRedis用于实现大部分官方的命令,并使用官方的语法和命令,
Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
Redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。
如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接
连接redis,加上decode_responses=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。
Redis是StrictRedis的子类,用于向后兼容旧版本的redis-py。
Redis连接实例是线程安全的,可以直接将redis连接实例设置为一个全局变量,直接使用。
如果需要另一个Redis实例(or Redis数据库)时,就需要重新创建redis连接实例来获取一个新的连接
连接redis,加上decode_responses=True,写入的键值对中的value为str类型,不加这个参数写入的则为字节类型。
Python Redis连接池
使用connection pool来管理对一个redis server的所有连接,避免每次建立、释放连接的开销。
默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,
然后作为参数传给Redis实例,这样就可以实现多个Redis实例共享一个连接池
默认,每个Redis实例都会维护一个自己的连接池。可以直接建立一个连接池,
然后作为参数传给Redis实例,这样就可以实现多个Redis实例共享一个连接池
redis的发布订阅者模式
redis订阅者
# by gaoxin
import redis
r = redis.Redis(host="127.0.0.1", password="", decode_responses=True)
# 第一步 生成一个订阅者对象
pubsub = r.pubsub()
# 第二步 订阅一个消息 实际上就是监听这个键
pubsub.subscribe("gaoxin")
# 第三步 死循环一直等待监听结果
while True:
print("working~~~")
msg = pubsub.parse_response()
print(msg)
import redis
r = redis.Redis(host="127.0.0.1", password="", decode_responses=True)
# 第一步 生成一个订阅者对象
pubsub = r.pubsub()
# 第二步 订阅一个消息 实际上就是监听这个键
pubsub.subscribe("gaoxin")
# 第三步 死循环一直等待监听结果
while True:
print("working~~~")
msg = pubsub.parse_response()
print(msg)
redis发布者
# by gaoxin
import redis
r = redis.Redis(host="127.0.0.1", password="", decode_responses=True)
r.publish("gaoxin", "hahaha")
import redis
r = redis.Redis(host="127.0.0.1", password="", decode_responses=True)
r.publish("gaoxin", "hahaha")
购物模块之结算中心
# by gaoxin
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.base_response import BaseResponse
from utils.redis_pool import pool
from django.utils.timezone import now
import redis
from utils.authentication import MyAuth
from .shop import SHOPPING_CAR_KEY
from pay.models import CouponRecord
from django.contrib.contenttypes.models import ContentType
import json
"""
结算中心
在购物车里选择了商品以及价格策略点击结算 才进入结算中心
在结算中心用户可以选择优惠券
传过来的数据 [course_id, course_id]
根据用户id 以及商品id 构建一个存入redis的key
SETTLEMENT_KEY = "settlement_%s_%s"
接下来构建结算中心数据结构
redis = {
settlement_用户id_课程id: {
"id": course.id, 带用户id是为了用户查看购物车的时候需要
"title": course.name,
"img": str(course.course_img),
"period_display": item.get_valid_period_display(), 价格策略中文
"price": item.price, 价格
"course_coupons": {
course_coupon_id: {...}
}
用户选中的优惠券id 在更新请求 也就是用户选了优惠券的时候更改
前端默认优惠券可以是不选的 根据业务决定
default_coupon_id: 1
}
global_coupon_用户id: {
global_coupon_id: {....},
# 在用户进入结算中心选择优惠券的时候 也就是更新请求的时候更改
default_global_coupon_id: 1
}
}
"""
SETTLEMENT_KEY = "settlement_%s_%s"
GLOBAL_COUPON_KEY = "global_coupon_%s"
REDIS_CONN = redis.Redis(connection_pool=pool)
class SettlementView(APIView):
"""
code为1020开始的都是结算中心的错误
1021 获取课程id失败
"""
authentication_classes = [MyAuth, ]
# 进入结算中心 也就是用户查看自己的未支付订单
def get(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 从redis结算中心获取数据并展示
# 根据用户id 得到 settlement_id_userid_*
user_id = request.user.pk
settlement_key = SETTLEMENT_KEY % (user_id, "*")
# scan_iter 得到所有的key
all_settlement_keys = REDIS_CONN.scan_iter(settlement_key)
global_coupon_key = GLOBAL_COUPON_KEY % user_id
# 2 循环遍历得到所有信息
settlement_list = []
for key in all_settlement_keys:
settlement_info = REDIS_CONN.hgetall(key)
settlement_list.append(settlement_info)
global_coupon_info = REDIS_CONN.hgetall(global_coupon_key)
res.data = {"settlement_list": settlement_list, "global_coupon_info": global_coupon_info}
except Exception as e:
res.code = 1024
res.error = "获取结算中心失败"
return Response(res.dict)
# 把商品添加到结算中心 用户传过来的数据是 【course_id,course_id】
def post(self, request, *args, **kwargs):
res = BaseResponse()
# 1 获取前端传过来的数据以及用户id
try:
course_list = request.data.get("course_list", "")
if not course_list:
res.code = 1021
res.error = "获取课程id失败"
return Response(res.dict)
user_id = request.user.pk
# 2 检查数据的合法性 查看课程id 是否在购物车中
for course_id in course_list:
# course_id = int(course_id)
shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1022
res.error = "结算的课程id不合法"
return Response(res.dict)
# 3 从购物车中获取课程的信息 并构建成结算中心的数据格式放入redis
# 3.1 先从redis中拿购物车中的数据
course_info = REDIS_CONN.hgetall(shopping_car_key)
# 3.2 获取用户所有符合条件优惠券
# 注意优惠券的使用期限以及状态
now_time = now()
# course_table_id = ContentType.objects.filter(app_label="course", model="course").first().pk
user_all_coupons = CouponRecord.objects.filter(
account_id=user_id,
status=0,
coupon__valid_begin_date__lte=now_time,
coupon__valid_end_date__gte=now_time,
# content_type_id=course_table_id,
# object_id=course_id
).all()
# 3.2 构建数据结构
course_coupons = {}
global_coupons = {}
for coupon_record in user_all_coupons:
# 证明这个优惠券是绑定课程的优惠券
coupon = coupon_record.coupon
if coupon.object_id == course_id:
course_coupons[coupon.id] = {
"name": coupon.name,
"coupon_type": coupon.get_coupon_type_display(),
"money_equivalent_value": coupon.money_equivalent_value,
"off_percent": coupon.off_percent,
"minimum_consume": coupon.minimum_consume,
"object_id": coupon.object_id,
}
elseif coupon.object_id == "":
global_coupons[coupon.id] = {
"name": coupon.name,
"coupon_type": coupon.get_coupon_type_display(),
"money_equivalent_value": coupon.money_equivalent_value,
"off_percent": coupon.off_percent,
"minimum_consume": coupon.minimum_consume,
"object_id": coupon.object_id,
}
# print(json.loads(course_info["price_policy_dict"]))
price_policy_dict = json.loads(course_info["price_policy_dict"])
default_policy_id = course_info["default_policy"]
price = price_policy_dict[default_policy_id]["price"]
print(price)
period_display = price_policy_dict[default_policy_id]["valid_period_text"]
print(period_display)
settlement_info = {
"id": course_info["id"],
"title": course_info["title"],
"img_src": course_info["img_src"],
"price": price,
"period_display": period_display,
"course_coupons": json.dumps(course_coupons, ensure_ascii=False),
}
# 3.3 准备构建结算中心的key
settlement_key = SETTLEMENT_KEY % (user_id, course_id)
global_coupon_key = GLOBAL_COUPON_KEY % user_id
# # 3.4 写入redis
REDIS_CONN.hmset(settlement_key, settlement_info)
print(global_coupons)
if global_coupons:
REDIS_CONN.hmset(global_coupon_key, global_coupons)
# # 4 加入结算中心成功 清除用户购物车中的相应课程的数据
REDIS_CONN.delete(shopping_car_key)
res.data = "加入结算中心成功"
except Exception as e:
print(e)
res.code = 1020
res.error = "结算失败"
return Response(res.dict)
# 用户在结算中心的时候更改优惠券
# 用户在选择优惠券的时候前端传过来course_id 以及coupon_id
# 如果选的是全局优惠券 就传 global_coupon_id
def patch(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 获取前端传过来的数据
course_id = request.data.get("course_id", "")
coupon_id = request.data.get("coupon_id", "")
global_coupon_id = request.data.get("global_coupon_id", "")
user_id = request.user.pk
# 2 校验数据的合法性
# 2.2 校验course_id是否合法
settlement_key = SETTLEMENT_KEY % (user_id, course_id)
if not REDIS_CONN.exists(settlement_key):
res.code = 1027
res.error = "课程id不合法"
return Response(res.dict)
# 2.3 校验coupon_id 是否合法
course_info = REDIS_CONN.hgetall(settlement_key)
course_coupon_dict = json.loads(course_info["course_coupons"])
if coupon_id not in course_coupon_dict:
res.code = 1028
res.error = "课程的优惠券不合法"
return Response(res.dict)
# 2.4 校验global_coupon_id是否合法 如果合法把默认的全局优惠信息放入redis
if global_coupon_id:
global_coupon_key = GLOBAL_COUPON_KEY % user_id
if not REDIS_CONN.exists(global_coupon_key):
res.code = 1029
res.error = "全局优惠券不合法"
return Response(res.dict)
REDIS_CONN.hset(global_coupon_key, "default_coupon_id", global_coupon_id)
# 3 给数据里加入默认选择的课程优惠券
REDIS_CONN.hset(settlement_key, "default_course_coupon_id", coupon_id)
res.data = "修改优惠券成功"
except Exception as e:
res.code = 1026
res.error = "更改优惠券失败"
return Response(res.dict)
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.base_response import BaseResponse
from utils.redis_pool import pool
from django.utils.timezone import now
import redis
from utils.authentication import MyAuth
from .shop import SHOPPING_CAR_KEY
from pay.models import CouponRecord
from django.contrib.contenttypes.models import ContentType
import json
"""
结算中心
在购物车里选择了商品以及价格策略点击结算 才进入结算中心
在结算中心用户可以选择优惠券
传过来的数据 [course_id, course_id]
根据用户id 以及商品id 构建一个存入redis的key
SETTLEMENT_KEY = "settlement_%s_%s"
接下来构建结算中心数据结构
redis = {
settlement_用户id_课程id: {
"id": course.id, 带用户id是为了用户查看购物车的时候需要
"title": course.name,
"img": str(course.course_img),
"period_display": item.get_valid_period_display(), 价格策略中文
"price": item.price, 价格
"course_coupons": {
course_coupon_id: {...}
}
用户选中的优惠券id 在更新请求 也就是用户选了优惠券的时候更改
前端默认优惠券可以是不选的 根据业务决定
default_coupon_id: 1
}
global_coupon_用户id: {
global_coupon_id: {....},
# 在用户进入结算中心选择优惠券的时候 也就是更新请求的时候更改
default_global_coupon_id: 1
}
}
"""
SETTLEMENT_KEY = "settlement_%s_%s"
GLOBAL_COUPON_KEY = "global_coupon_%s"
REDIS_CONN = redis.Redis(connection_pool=pool)
class SettlementView(APIView):
"""
code为1020开始的都是结算中心的错误
1021 获取课程id失败
"""
authentication_classes = [MyAuth, ]
# 进入结算中心 也就是用户查看自己的未支付订单
def get(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 从redis结算中心获取数据并展示
# 根据用户id 得到 settlement_id_userid_*
user_id = request.user.pk
settlement_key = SETTLEMENT_KEY % (user_id, "*")
# scan_iter 得到所有的key
all_settlement_keys = REDIS_CONN.scan_iter(settlement_key)
global_coupon_key = GLOBAL_COUPON_KEY % user_id
# 2 循环遍历得到所有信息
settlement_list = []
for key in all_settlement_keys:
settlement_info = REDIS_CONN.hgetall(key)
settlement_list.append(settlement_info)
global_coupon_info = REDIS_CONN.hgetall(global_coupon_key)
res.data = {"settlement_list": settlement_list, "global_coupon_info": global_coupon_info}
except Exception as e:
res.code = 1024
res.error = "获取结算中心失败"
return Response(res.dict)
# 把商品添加到结算中心 用户传过来的数据是 【course_id,course_id】
def post(self, request, *args, **kwargs):
res = BaseResponse()
# 1 获取前端传过来的数据以及用户id
try:
course_list = request.data.get("course_list", "")
if not course_list:
res.code = 1021
res.error = "获取课程id失败"
return Response(res.dict)
user_id = request.user.pk
# 2 检查数据的合法性 查看课程id 是否在购物车中
for course_id in course_list:
# course_id = int(course_id)
shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1022
res.error = "结算的课程id不合法"
return Response(res.dict)
# 3 从购物车中获取课程的信息 并构建成结算中心的数据格式放入redis
# 3.1 先从redis中拿购物车中的数据
course_info = REDIS_CONN.hgetall(shopping_car_key)
# 3.2 获取用户所有符合条件优惠券
# 注意优惠券的使用期限以及状态
now_time = now()
# course_table_id = ContentType.objects.filter(app_label="course", model="course").first().pk
user_all_coupons = CouponRecord.objects.filter(
account_id=user_id,
status=0,
coupon__valid_begin_date__lte=now_time,
coupon__valid_end_date__gte=now_time,
# content_type_id=course_table_id,
# object_id=course_id
).all()
# 3.2 构建数据结构
course_coupons = {}
global_coupons = {}
for coupon_record in user_all_coupons:
# 证明这个优惠券是绑定课程的优惠券
coupon = coupon_record.coupon
if coupon.object_id == course_id:
course_coupons[coupon.id] = {
"name": coupon.name,
"coupon_type": coupon.get_coupon_type_display(),
"money_equivalent_value": coupon.money_equivalent_value,
"off_percent": coupon.off_percent,
"minimum_consume": coupon.minimum_consume,
"object_id": coupon.object_id,
}
elseif coupon.object_id == "":
global_coupons[coupon.id] = {
"name": coupon.name,
"coupon_type": coupon.get_coupon_type_display(),
"money_equivalent_value": coupon.money_equivalent_value,
"off_percent": coupon.off_percent,
"minimum_consume": coupon.minimum_consume,
"object_id": coupon.object_id,
}
# print(json.loads(course_info["price_policy_dict"]))
price_policy_dict = json.loads(course_info["price_policy_dict"])
default_policy_id = course_info["default_policy"]
price = price_policy_dict[default_policy_id]["price"]
print(price)
period_display = price_policy_dict[default_policy_id]["valid_period_text"]
print(period_display)
settlement_info = {
"id": course_info["id"],
"title": course_info["title"],
"img_src": course_info["img_src"],
"price": price,
"period_display": period_display,
"course_coupons": json.dumps(course_coupons, ensure_ascii=False),
}
# 3.3 准备构建结算中心的key
settlement_key = SETTLEMENT_KEY % (user_id, course_id)
global_coupon_key = GLOBAL_COUPON_KEY % user_id
# # 3.4 写入redis
REDIS_CONN.hmset(settlement_key, settlement_info)
print(global_coupons)
if global_coupons:
REDIS_CONN.hmset(global_coupon_key, global_coupons)
# # 4 加入结算中心成功 清除用户购物车中的相应课程的数据
REDIS_CONN.delete(shopping_car_key)
res.data = "加入结算中心成功"
except Exception as e:
print(e)
res.code = 1020
res.error = "结算失败"
return Response(res.dict)
# 用户在结算中心的时候更改优惠券
# 用户在选择优惠券的时候前端传过来course_id 以及coupon_id
# 如果选的是全局优惠券 就传 global_coupon_id
def patch(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 获取前端传过来的数据
course_id = request.data.get("course_id", "")
coupon_id = request.data.get("coupon_id", "")
global_coupon_id = request.data.get("global_coupon_id", "")
user_id = request.user.pk
# 2 校验数据的合法性
# 2.2 校验course_id是否合法
settlement_key = SETTLEMENT_KEY % (user_id, course_id)
if not REDIS_CONN.exists(settlement_key):
res.code = 1027
res.error = "课程id不合法"
return Response(res.dict)
# 2.3 校验coupon_id 是否合法
course_info = REDIS_CONN.hgetall(settlement_key)
course_coupon_dict = json.loads(course_info["course_coupons"])
if coupon_id not in course_coupon_dict:
res.code = 1028
res.error = "课程的优惠券不合法"
return Response(res.dict)
# 2.4 校验global_coupon_id是否合法 如果合法把默认的全局优惠信息放入redis
if global_coupon_id:
global_coupon_key = GLOBAL_COUPON_KEY % user_id
if not REDIS_CONN.exists(global_coupon_key):
res.code = 1029
res.error = "全局优惠券不合法"
return Response(res.dict)
REDIS_CONN.hset(global_coupon_key, "default_coupon_id", global_coupon_id)
# 3 给数据里加入默认选择的课程优惠券
REDIS_CONN.hset(settlement_key, "default_course_coupon_id", coupon_id)
res.data = "修改优惠券成功"
except Exception as e:
res.code = 1026
res.error = "更改优惠券失败"
return Response(res.dict)
三方服务之微信消息推送
微信模板消息
1, 关注我的公众号
-- 让用户扫码关注
-- 这个时候用户只能看我发表的文章
2, 引导用户做授权
-- 目的 让用户告诉微信他允许微信把他的微信id
发给这个公众号
-- 让用户给微信指定的url发请求
URL?app_id="公众号的ID"&state=uid&redirect_uri="回调地址"
-- 把上面的url生成二维码给用户
-- 微信要做二次验证 相当于跟我们握手
给我们配置的redirect_uri="回调地址"发请求
微信携带 code= "xxx" state=uid
再回调地址对应的视图函数里
再给微信发请求{
appID
secret_key
code
}
获取wx_id
保存到数据库
3, 发送消息
-- 1, 获取认证access_token
理解为我们登陆后的认证标识
相当于我们去微信那里登陆后微信给我返回一个token
token的有效期2小时
-- 2,发送消息
发送消息的接口urlxxxxxxxxx?access_token=""
发送什么样的消息就去调用什么样的接口
1, 关注我的公众号
-- 让用户扫码关注
-- 这个时候用户只能看我发表的文章
2, 引导用户做授权
-- 目的 让用户告诉微信他允许微信把他的微信id
发给这个公众号
-- 让用户给微信指定的url发请求
URL?app_id="公众号的ID"&state=uid&redirect_uri="回调地址"
-- 把上面的url生成二维码给用户
-- 微信要做二次验证 相当于跟我们握手
给我们配置的redirect_uri="回调地址"发请求
微信携带 code= "xxx" state=uid
再回调地址对应的视图函数里
再给微信发请求{
appID
secret_key
code
}
获取wx_id
保存到数据库
3, 发送消息
-- 1, 获取认证access_token
理解为我们登陆后的认证标识
相当于我们去微信那里登陆后微信给我返回一个token
token的有效期2小时
-- 2,发送消息
发送消息的接口urlxxxxxxxxx?access_token=""
发送什么样的消息就去调用什么样的接口
三方服务之保利威视频播放
保利威视频的播放
加密播放 -- 防下载
-- H5播放器
vid: "",
playsafe: "token"
playsafe: function(vid, next){
do something.....
next("token")
}
-- 获取token
向保利威提供的接口发POST请求
URL: "https://hls.videocc.net/service/v1/token"
Content-Type : urlencoded
data: {按照文档的要求携带数据}
response = {status: 200, message: "error", "token": "随机字符串" }
-- POST请求携带的数据
-- 1 # POST请求携带的数据
data = {
"userId": self.USER_ID,
"videoId": vid,
"ts": time_stamp,
"viewerIp": remote_addr,(看视频的IP地址)
"viewerId": uid,
"viewerName": username,
"extraParams": extra_params,
"sign": "xxxxxx"
}
-- 获得 sign
"userId": self.USER_ID,
"videoId": vid,
"ts": time_stamp,
"viewerIp": remote_addr,(看视频的IP地址)
"viewerId": uid,
"viewerName": username,
"extraParams": extra_params,
-- 1 把上面的数据按照ASCII升序排列
-- 2 前后加secret_key
-- 3 取MD5加密的大写
跑马灯播放 -- 防盗录
前端
要求你用新js
code : MyRandomCode
后端
1 当我们用新的js播放器播放开启跑马灯的视频的时候
2 保利威会向我们配置的回调的url发送GET请求
3 在URL携带?vid=xx&code=xxx&t=xxx&callback=xxx
4 要求你这个接口返回Json数据
{
"status": status,
"username": username,
"sign": sign,
"msg": msg,
"fontSize": "18",
"fontColor": "0xFF0000",
"speed": "50",
"filter": "on",
"setting": "2",
"alpha": "0.7",
"filterAlpha": "1",
"filterColor": "0x3914AF",
"blurX": "2",
"blurY": "2",
"tweenTime": "1",
"interval": "3",
"lifeTime": "3",
"strength": "4",
"show": "on"
}
5 sign的获取
self.generate_md5_num("vid={}&secretkey={}&username={}&code={}&status={}&t={}".format(
vid, self.SECRET_KEY, username, code, status, t
)).lower()
加密播放 -- 防下载
-- H5播放器
vid: "",
playsafe: "token"
playsafe: function(vid, next){
do something.....
next("token")
}
-- 获取token
向保利威提供的接口发POST请求
URL: "https://hls.videocc.net/service/v1/token"
Content-Type : urlencoded
data: {按照文档的要求携带数据}
response = {status: 200, message: "error", "token": "随机字符串" }
-- POST请求携带的数据
-- 1 # POST请求携带的数据
data = {
"userId": self.USER_ID,
"videoId": vid,
"ts": time_stamp,
"viewerIp": remote_addr,(看视频的IP地址)
"viewerId": uid,
"viewerName": username,
"extraParams": extra_params,
"sign": "xxxxxx"
}
-- 获得 sign
"userId": self.USER_ID,
"videoId": vid,
"ts": time_stamp,
"viewerIp": remote_addr,(看视频的IP地址)
"viewerId": uid,
"viewerName": username,
"extraParams": extra_params,
-- 1 把上面的数据按照ASCII升序排列
-- 2 前后加secret_key
-- 3 取MD5加密的大写
跑马灯播放 -- 防盗录
前端
要求你用新js
code : MyRandomCode
后端
1 当我们用新的js播放器播放开启跑马灯的视频的时候
2 保利威会向我们配置的回调的url发送GET请求
3 在URL携带?vid=xx&code=xxx&t=xxx&callback=xxx
4 要求你这个接口返回Json数据
{
"status": status,
"username": username,
"sign": sign,
"msg": msg,
"fontSize": "18",
"fontColor": "0xFF0000",
"speed": "50",
"filter": "on",
"setting": "2",
"alpha": "0.7",
"filterAlpha": "1",
"filterColor": "0x3914AF",
"blurX": "2",
"blurY": "2",
"tweenTime": "1",
"interval": "3",
"lifeTime": "3",
"strength": "4",
"show": "on"
}
5 sign的获取
self.generate_md5_num("vid={}&secretkey={}&username={}&code={}&status={}&t={}".format(
vid, self.SECRET_KEY, username, code, status, t
)).lower()
登录认证模块
认证
任何的项目都需要认证,用户输入了用户名和密码,验证通过,代表用户登录成功~~~
HTTP请求是无状态的,下次这个用户再请求,我们是不可能识别这个用户是否登录的~~
HTTP请求是无状态的,下次这个用户再请求,我们是不可能识别这个用户是否登录的~~
TOKEN
用户登录成功后,生成一个随机字符串token给前端返回~~~
那么前端以后都携带这个token来访问~~这样我们只需要鉴别这个token~来做认证~~
那么前端以后都携带这个token来访问~~这样我们只需要鉴别这个token~来做认证~~
购物模块之购物车
from rest_framework.views import APIView
from rest_framework.response import Response
from utils.authentication import MyAuth
from utils.redis_pool import pool
from utils.base_response import BaseResponse
from course.models import Course
import redis
import json
"""
购物车
redis 的数据结构设计
redis = {
shopping_car_<user_id>_<course_id>: {
"id": course.id, 带用户id是为了用户查看购物车的时候需要
"title": course.name,
"img": str(course.course_img),
"policy_dict": {
policy_id:{
"period": item.valid_period, 价格策略
"period_display": item.get_valid_period_display(), 价格策略中文
"price": item.price, 价格
},
policy_id2:{
....
}
},
"default_policy": policy_id ,选择的价格策略id
}
}
"""
REDIS_CONN = redis.Redis(connection_pool=pool)
SHOPPING_CAR_KEY = "shopping_car_%s_%s"
class ShoppingCarView(APIView):
"""
购物车接口
1010 代表成功
1011 课程不存在
1012 价格策略不存在
1013 获取购物车失败
1014 删除的购物车数据不存在
"""
authentication_classes = [MyAuth, ]
# 展示购物车数据
def get(self, request, *args, **kwargs):
res = BaseResponse()
# 1 从redis获取购物车数据
try:
user_id = request.user.pk
shopping_car_key = SHOPPING_CAR_KEY % (user_id, "*")
# 用scan_iter方法获取用户购物车的所有key
all_keys = REDIS_CONN.scan_iter(shopping_car_key)
ret = []
# 循环得到所有想要的数据
for key in all_keys:print(REDIS_CONN.hgetall(key))
ret.append(REDIS_CONN.hgetall(key))
res.data = ret
except Exception as e:
res.code = 1013
res.error = "获取购物车失败"
return Response(res.dict)
# 给购物车增加商品
# 传过来的数据 有 课程ID 以及价格策略ID
def post(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 获取用户提交的课程ID以及价格策略ID
course_id = request.data.get("course_id", "")
price_policy_id = request.data.get("price_policy_id", "")
user_id = request.user.pk
# 2 检查用户传过来的数据是否合法
# 2.1 查看课程ID是否存在
course_obj = Course.objects.filter(pk=course_id).first()
if not course_obj:
res.code = 1011
res.error = "课程对象不存在"
# 2.2 查看价格策略是否合法
# 获取该课程的所有价格策略
price_policy_queryset = course_obj.price_policy.all()
price_policy_dict = {}
for price_policy in price_policy_queryset:
price_policy_dict[price_policy.pk] = {
"price": price_policy.price,
"valid_period": price_policy.valid_period,
"valid_period_text": price_policy.get_valid_period_display(),
}
if price_policy_id not in price_policy_dict:
res.code = 1012
res.error = "课程的价格策略不存在"
# 3 用户数据合法 得到用户的购物车key
shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
# 4 构建购物车数据
course_info = {
"id": course_id,
"title": course_obj.title,
"img_src": str(course_obj.course_img),
"default_policy": price_policy_id,
"price_policy_dict": json.dumps(price_policy_dict)
}
# 5 写入redis hmset这个方法有值就更新 没值就新建 解决了用户重复点一个商品的问题
REDIS_CONN.hmset(shopping_car_key, course_info)
res.data = "加入购物车成功"
except Exception as e:
print(e)
res.code = 1010
res.error = "加入购物车失败"
return Response(res.dict)
# 删除购物车数据
# 传过来的数据 {course_ids: [1,2]}
def delete(self, request, *args, **kwargs):
res = BaseResponse()
# 1 验证数据合法性 课程ID是否在购物车里
try:
for course_id in request.data["course_ids"]:
shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1014
res.error = "课程不存在购物车"
# 2 数据合法 删除redis购物车里的数据
REDIS_CONN.delete(shopping_car_key)
except Exception as e:
res.code = 1015
res.error = "删除购物车失败"
return Response(res.dict)
# 更新购物车里的课程的价格策略
# 传过来的数据 有 course_id 以及 price_policy_id
def patch(self, request, *args, **kwargs):
res = BaseResponse()
# 1 验证数据的合法性 course_id 以及 policy_id
try:
course_id = request.data["course_id"]
policy_id = request.data["price_policy_id"]
# 判断redis购物车里是否有course_id
shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1014
res.error = "课程不存在购物车"
# 判断policy_id 是否合法
price_policy_dict = json.loads(REDIS_CONN.hget(shopping_car_key, "price_policy_dict"))
if str(policy_id) not in price_policy_dict:
res.code = 1015
res.error = "价格策略不合法"
# 2 更改购物车里的数据
REDIS_CONN.hset(shopping_car_key, "default_policy", policy_id)
except Exception as e:
print(e)
res.code = 1016
res.error = "更新购物车失败"
return Response(res.dict)
from rest_framework.response import Response
from utils.authentication import MyAuth
from utils.redis_pool import pool
from utils.base_response import BaseResponse
from course.models import Course
import redis
import json
"""
购物车
redis 的数据结构设计
redis = {
shopping_car_<user_id>_<course_id>: {
"id": course.id, 带用户id是为了用户查看购物车的时候需要
"title": course.name,
"img": str(course.course_img),
"policy_dict": {
policy_id:{
"period": item.valid_period, 价格策略
"period_display": item.get_valid_period_display(), 价格策略中文
"price": item.price, 价格
},
policy_id2:{
....
}
},
"default_policy": policy_id ,选择的价格策略id
}
}
"""
REDIS_CONN = redis.Redis(connection_pool=pool)
SHOPPING_CAR_KEY = "shopping_car_%s_%s"
class ShoppingCarView(APIView):
"""
购物车接口
1010 代表成功
1011 课程不存在
1012 价格策略不存在
1013 获取购物车失败
1014 删除的购物车数据不存在
"""
authentication_classes = [MyAuth, ]
# 展示购物车数据
def get(self, request, *args, **kwargs):
res = BaseResponse()
# 1 从redis获取购物车数据
try:
user_id = request.user.pk
shopping_car_key = SHOPPING_CAR_KEY % (user_id, "*")
# 用scan_iter方法获取用户购物车的所有key
all_keys = REDIS_CONN.scan_iter(shopping_car_key)
ret = []
# 循环得到所有想要的数据
for key in all_keys:print(REDIS_CONN.hgetall(key))
ret.append(REDIS_CONN.hgetall(key))
res.data = ret
except Exception as e:
res.code = 1013
res.error = "获取购物车失败"
return Response(res.dict)
# 给购物车增加商品
# 传过来的数据 有 课程ID 以及价格策略ID
def post(self, request, *args, **kwargs):
res = BaseResponse()
try:
# 1 获取用户提交的课程ID以及价格策略ID
course_id = request.data.get("course_id", "")
price_policy_id = request.data.get("price_policy_id", "")
user_id = request.user.pk
# 2 检查用户传过来的数据是否合法
# 2.1 查看课程ID是否存在
course_obj = Course.objects.filter(pk=course_id).first()
if not course_obj:
res.code = 1011
res.error = "课程对象不存在"
# 2.2 查看价格策略是否合法
# 获取该课程的所有价格策略
price_policy_queryset = course_obj.price_policy.all()
price_policy_dict = {}
for price_policy in price_policy_queryset:
price_policy_dict[price_policy.pk] = {
"price": price_policy.price,
"valid_period": price_policy.valid_period,
"valid_period_text": price_policy.get_valid_period_display(),
}
if price_policy_id not in price_policy_dict:
res.code = 1012
res.error = "课程的价格策略不存在"
# 3 用户数据合法 得到用户的购物车key
shopping_car_key = SHOPPING_CAR_KEY % (user_id, course_id)
# 4 构建购物车数据
course_info = {
"id": course_id,
"title": course_obj.title,
"img_src": str(course_obj.course_img),
"default_policy": price_policy_id,
"price_policy_dict": json.dumps(price_policy_dict)
}
# 5 写入redis hmset这个方法有值就更新 没值就新建 解决了用户重复点一个商品的问题
REDIS_CONN.hmset(shopping_car_key, course_info)
res.data = "加入购物车成功"
except Exception as e:
print(e)
res.code = 1010
res.error = "加入购物车失败"
return Response(res.dict)
# 删除购物车数据
# 传过来的数据 {course_ids: [1,2]}
def delete(self, request, *args, **kwargs):
res = BaseResponse()
# 1 验证数据合法性 课程ID是否在购物车里
try:
for course_id in request.data["course_ids"]:
shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1014
res.error = "课程不存在购物车"
# 2 数据合法 删除redis购物车里的数据
REDIS_CONN.delete(shopping_car_key)
except Exception as e:
res.code = 1015
res.error = "删除购物车失败"
return Response(res.dict)
# 更新购物车里的课程的价格策略
# 传过来的数据 有 course_id 以及 price_policy_id
def patch(self, request, *args, **kwargs):
res = BaseResponse()
# 1 验证数据的合法性 course_id 以及 policy_id
try:
course_id = request.data["course_id"]
policy_id = request.data["price_policy_id"]
# 判断redis购物车里是否有course_id
shopping_car_key = SHOPPING_CAR_KEY % (request.user.pk, course_id)
if not REDIS_CONN.exists(shopping_car_key):
res.code = 1014
res.error = "课程不存在购物车"
# 判断policy_id 是否合法
price_policy_dict = json.loads(REDIS_CONN.hget(shopping_car_key, "price_policy_dict"))
if str(policy_id) not in price_policy_dict:
res.code = 1015
res.error = "价格策略不合法"
# 2 更改购物车里的数据
REDIS_CONN.hset(shopping_car_key, "default_policy", policy_id)
except Exception as e:
print(e)
res.code = 1016
res.error = "更新购物车失败"
return Response(res.dict)
购物模块之支付中心
支付接口
前端会传过来 price banlance
1, 获取前端传过来的数据 以及user_id
2,校验数据的合法性 price banlance
!! redis中结算中心的数据跟支付的时候有时间差
!! 优惠券过期 商品下架
-- 校验贝里
-- 跟数据库用户的贝里余额去校验
-- 校验课程是否下架
-- 从redis中的结算中心拿课程id 去数据库校验是否下架
-- 优惠券是否过期
-- 校验课程的优惠券
-- 从redis结算中心取default_course_coupon_id
去数据库校验这个优惠券对象是否过期
-- 校验全局优惠券
-- 从redis全局优惠券取default_global_coupon_id
去数据库校验这个优惠券对象是否过期
-- 校验价格
-- 先得到所有课程的折后价格的总和
-- 课程折后总价跟全局优惠券去做计算
-- 抵扣贝里
-- 得到最终价格跟price校验
3, 数据合法 建议一个订单
4,掉支付宝接口去支付
5,notify_url 修改订单以及订单详情 优惠券 贝里
!!! 做计算都是浮点型或整形
!!! 设计数据库的时候尽量不要有null 给默认值
前端会传过来 price banlance
1, 获取前端传过来的数据 以及user_id
2,校验数据的合法性 price banlance
!! redis中结算中心的数据跟支付的时候有时间差
!! 优惠券过期 商品下架
-- 校验贝里
-- 跟数据库用户的贝里余额去校验
-- 校验课程是否下架
-- 从redis中的结算中心拿课程id 去数据库校验是否下架
-- 优惠券是否过期
-- 校验课程的优惠券
-- 从redis结算中心取default_course_coupon_id
去数据库校验这个优惠券对象是否过期
-- 校验全局优惠券
-- 从redis全局优惠券取default_global_coupon_id
去数据库校验这个优惠券对象是否过期
-- 校验价格
-- 先得到所有课程的折后价格的总和
-- 课程折后总价跟全局优惠券去做计算
-- 抵扣贝里
-- 得到最终价格跟price校验
3, 数据合法 建议一个订单
4,掉支付宝接口去支付
5,notify_url 修改订单以及订单详情 优惠券 贝里
!!! 做计算都是浮点型或整形
!!! 设计数据库的时候尽量不要有null 给默认值
三方服务之支付宝支付
支付宝的支付
1,生成应用的公钥和私钥 注意选择非java适用
2,在沙箱环境里放你应用的公钥
3,在项目里 放的你应用的私钥以及支付宝的公钥
1,生成应用的公钥和私钥 注意选择非java适用
2,在沙箱环境里放你应用的公钥
3,在项目里 放的你应用的私钥以及支付宝的公钥
三方服务之滑动验证码
-- 在你需要用滑动验证码的页面
默认发一个ajax GET请求
http://127.0.0.1:8000/pc-geetest/register?t=" + (new Date()).getTime(),
返回值
gt challenge success
-- 发送请求成功
initGeetest({config}, function)
config: {
gt: gt
challenge
success
product: "popup"
}
执行回调函数function(验证码对象)
-- 回调函数里
-- 发送请求 POST请求
"http://127.0.0.1:8000/pc-geetest/ajax_validate"
data: {
username: that.username,
password: that.pwd,
geetest_challenge: validate.geetest_challenge,
geetest_validate: validate.geetest_validate,
geetest_seccode: validate.geetest_seccode
}
请求成功的回调函数
获取后端返回的信息 显示是否登录成功
-- that.$refs.submit.onclick = function () {
captchaObj.show();
};
// 点击登录显示验证码
-- captchaObj.appendTo("#popup-captcha");
// 将验证码加到id为captcha的元素里
Django的Cookie和Session
设置session
request.session["key"] = value
获取session
request.session.get("")
设置Cookie
response.Cookie.set()
获取Cookie
Cookie.get()
默认发一个ajax GET请求
http://127.0.0.1:8000/pc-geetest/register?t=" + (new Date()).getTime(),
返回值
gt challenge success
-- 发送请求成功
initGeetest({config}, function)
config: {
gt: gt
challenge
success
product: "popup"
}
执行回调函数function(验证码对象)
-- 回调函数里
-- 发送请求 POST请求
"http://127.0.0.1:8000/pc-geetest/ajax_validate"
data: {
username: that.username,
password: that.pwd,
geetest_challenge: validate.geetest_challenge,
geetest_validate: validate.geetest_validate,
geetest_seccode: validate.geetest_seccode
}
请求成功的回调函数
获取后端返回的信息 显示是否登录成功
-- that.$refs.submit.onclick = function () {
captchaObj.show();
};
// 点击登录显示验证码
-- captchaObj.appendTo("#popup-captcha");
// 将验证码加到id为captcha的元素里
Django的Cookie和Session
设置session
request.session["key"] = value
获取session
request.session.get("")
设置Cookie
response.Cookie.set()
获取Cookie
Cookie.get()
0 条评论
下一页