11.15luffycity(7)
2018-11-15 17:43:50
还有一点路飞项目就结束啦!
周日打算回去!
双十一的耳机到啦,音质确实不错!2333!
等着项目做完,完整总结一下!
越努力,越幸运!永远不要高估自己!!!!
贴上源码!
今天老师实现了结算中心 显示课程,修改优惠券和其他的东西
整体逻辑不难,思路清晰,易于理解
payment.py
from rest_framework.views import APIView
from rest_framework.response import Response
from app01.utils.auth import LuffyAuth
from django.conf import settings
from django_redis import get_redis_connection
import json
from app01.utils.response import BaseResponse
from app01 import models
import datetime class PaymentViewSet(APIView):
authentication_classes = [LuffyAuth, ]
conn = get_redis_connection("default") def post(self, request, *args, **kwargs):
"""
获取用户要结算的课程和优惠券
:param request:
:param args:
:param kwargs:
:return:
"""
ret = BaseResponse()
try:
# 清空当前用户结算中心的数据
# luffy_payment_1_*
# luffy_payment_coupon_1
key_list = self.conn.keys(settings.PAYMENT_KEY % (request.auth.user_id, "*",))
key_list.append(settings.PAYMENT_COUPON_KEY % (request.auth.user_id,))
self.conn.delete(*key_list)
payment_dict = {}
global_coupon_dict = {
"coupon": {},
"default_coupon": 0
}
# 1. 获取用户要结算课程ID
course_id_list = request.data.get('courseids')
for course_id in course_id_list:
car_key = settings.SHOPPING_CAR_KEY % (request.auth.user_id, course_id,) # 1.1 检测用户要结算的课程是否已经加入购物车
if not self.conn.exists(car_key):
ret.code = 1001
ret.error = "课程需要先加入购物车才能结算"
# 1.2 从购物车中获取信息,放入到结算中心。
# 获取标题和图片
policy = json.loads(self.conn.hget(car_key, 'policy').decode('utf-8'))
default_policy = self.conn.hget(car_key, 'default_policy').decode('utf-8')
policy_info = policy[default_policy] payment_course_dict = {
"course_id": str(course_id),
"title": self.conn.hget(car_key, 'title').decode('utf-8'),
"img": self.conn.hget(car_key, 'img').decode('utf-8'),
"policy_id": default_policy,
"coupon": {},
"default_coupon": 0
}
payment_course_dict.update(policy_info)
payment_dict[str(course_id)] = payment_course_dict
# 2. 获取优惠券
ctime = datetime.date.today()
coupon_list = models.CouponRecord.objects.filter(
account=request.auth.user,
status=0,
coupon__valid_begin_date__lte=ctime,
coupon__valid_end_date__gte=ctime,
)
for item in coupon_list: # 只处理绑定课程的优惠券
if not item.coupon.object_id:
# 优惠券ID
coupon_id = item.id # 优惠券类型:满减、折扣、立减
coupon_type = item.coupon.coupon_type info = {}
info['coupon_type'] = coupon_type
info['coupon_display'] = item.coupon.get_coupon_type_display()
if coupon_type == 0: # 立减
info['money_equivalent_value'] = item.coupon.money_equivalent_value
elif coupon_type == 1: # 满减券
info['money_equivalent_value'] = item.coupon.money_equivalent_value
info['minimum_consume'] = item.coupon.minimum_consume
else: # 折扣
info['off_percent'] = item.coupon.off_percent global_coupon_dict['coupon'][coupon_id] = info continue
# 优惠券绑定课程的ID
coupon_course_id = str(item.coupon.object_id) # 优惠券ID
coupon_id = item.id # 优惠券类型:满减、折扣、立减
coupon_type = item.coupon.coupon_type info = {}
info['coupon_type'] = coupon_type
info['coupon_display'] = item.coupon.get_coupon_type_display()
if coupon_type == 0: # 立减
info['money_equivalent_value'] = item.coupon.money_equivalent_value
elif coupon_type == 1: # 满减券
info['money_equivalent_value'] = item.coupon.money_equivalent_value
info['minimum_consume'] = item.coupon.minimum_consume
else: # 折扣
info['off_percent'] = item.coupon.off_percent if coupon_course_id not in payment_dict:
# 获取到优惠券,但是没有购买此课程
continue
# 将优惠券设置到指定的课程字典中
payment_dict[coupon_course_id]['coupon'][coupon_id] = info
# 可以获取绑定的优惠券
# 3. 将绑定优惠券课程+全站优惠券 写入到redis中(结算中心)。
# 3.1 绑定优惠券课程放入redis
for cid, cinfo in payment_dict.items():
pay_key = settings.PAYMENT_KEY % (request.auth.user_id, cid,)
cinfo['coupon'] = json.dumps(cinfo['coupon'])
self.conn.hmset(pay_key, cinfo)
# 3.2 将全站优惠券写入redis
gcoupon_key = settings.PAYMENT_COUPON_KEY % (request.auth.user_id,)
global_coupon_dict['coupon'] = json.dumps(global_coupon_dict['coupon'])
self.conn.hmset(gcoupon_key, global_coupon_dict) except Exception as e:
pass return Response(ret.dict) def patch(self, request, *args, **kwargs):
"""
修改优惠券
:param request:
:param args:
:param kwargs:
:return:
"""
ret = BaseResponse()
try:
# 1. 用户提交要修改的优惠券
course = request.data.get('courseid')
course_id = str(course) if course else course coupon_id = str(request.data.get('couponid')) # payment_global_coupon_1
redis_global_coupon_key = settings.PAYMENT_COUPON_KEY % (request.auth.user_id,) # 修改全站优惠券
if not course_id:
if coupon_id == "":
# 不使用优惠券,请求数据:{"couponid":0}
self.conn.hset(redis_global_coupon_key, 'default_coupon', coupon_id)
ret.data = "修改成功"
return Response(ret.dict)
# 使用优惠券,请求数据:{"couponid":2}
coupon_dict = json.loads(self.conn.hget(redis_global_coupon_key, 'coupon').decode('utf-8')) # 判断用户选择得优惠券是否合法
if coupon_id not in coupon_dict:
ret.code = 1001
ret.error = "全站优惠券不存在"
return Response(ret.dict) # 选择的优惠券合法
self.conn.hset(redis_global_coupon_key, 'default_coupon', coupon_id)
ret.data = "修改成功"
return Response(ret.dict) # 修改课程优惠券
# luffy_payment_1_1
redis_payment_key = settings.PAYMENT_KEY % (request.auth.user_id, course_id,)
# 不使用优惠券
if coupon_id == "":
self.conn.hset(redis_payment_key, 'default_coupon', coupon_id)
ret.data = "修改成功"
return Response(ret.dict) # 使用优惠券
coupon_dict = json.loads(self.conn.hget(redis_payment_key, 'coupon').decode('utf-8'))
if coupon_id not in coupon_dict:
ret.code = 1010
ret.error = "课程优惠券不存在"
return Response(ret.dict) self.conn.hset(redis_payment_key, 'default_coupon', coupon_id) except Exception as e:
ret.code = 1111
ret.error = "修改失败" return Response(ret.dict) def get(self, request, *args, **kwargs):
"""
结算中心展示页面(用户访问)
:param request:
:param args:
:param kwargs:
:return:
"""
ret = BaseResponse()
try:
# luffy_payment_1_*
redis_payment_key = settings.PAYMENT_KEY % (request.auth.user_id, "*",)
# luffy_payment_coupon_1
redis_global_coupon_key = settings.PAYMENT_COUPON_KEY % (request.auth.user_id,)
# 1. 获取绑定课程信息
course_list = []
for key in self.conn.scan_iter(redis_payment_key):
info = {}
data = self.conn.hgetall(key)
for k, v in data.items():
kk = k.decode('utf-8')
if kk == "coupon":
info[kk] = json.loads(v.decode('utf-8'))
else:
info[kk] = v.decode('utf-8')
course_list.append(info) # 2.全站优惠券
global_coupon_dict = {
'coupon': json.loads(self.conn.hget(redis_global_coupon_key, 'coupon').decode('utf-8')),
'default_coupon': self.conn.hget(redis_global_coupon_key, 'default_coupon').decode('utf-8')
} ret.data = {
"course_list": course_list,
"global_coupon_dict": global_coupon_dict
}
except Exception as e:
ret.code = 1001
ret.error = "获取失败" return Response(ret.dict)
放上笔记
s9day113 内容回顾:
1. 路飞学城的购物车如何实现? 2. 商品是否有个数?
- 价格策略(用事件来类比个数)
- 购买之后就开始计时 3. 购物车在redis的结构? 4. 购物车购买数量有限制吗?
.keys('xxxxx')
5. 购物车是否设置超时时间?
.conn.expire("shopping_car_1_1" ,60*30) 方案:购买课程个数限制(200个) 6. 为什么把购物车信息放入redis?
- 临时状态
- 频繁修改的话,速度快。 7. 具体购物车的逻辑?
添加:
1. 用户选择:课程、价格策略,提交
2. 获取课程、价格策略进行合法性校验(数据库查询)
3. 数据获取,构造结构:
{
shopping_car_用户ID_课程ID:{
title:"...",
img:'xxx',
policy:{
...
}
}
}
4. 将数据以字典的形式保存到redis中。
修改:
1. 用户选择:课程、价格策略,提交
2. 获取课程、价格策略进行合法性校验(redis查询)
3. 更新价格策略
删除:
1. 用户选择:课程提交
2. 获取课程合法性校验(redis查询)
3. 删除
查看:
1. 构造Key shopping_car_用户ID_*
2. scan_iter 8. 原则:
- 简答逻辑先处理
- try
- 细粒度异常+自定义异常
- 导入模块
- 内置
- 框架
- 自定义
- 注释
- 文件
- 类
- 函数
- 文件名、类、函数、project
- 对功能进行分类
- 减少代码层级
- BaseResponse 今日内容:
- 结算中心
- 去支付 内容详细:
1. 结算中心
a. 添加到结算中心:
请求:POST
数据:
{
courseids:[1,2]
} Q补充:
con = {
"id":1,
"age__gt":9,
"name__lt": 8
"name__lt": 8
} # 构造AND
models.User.objects.filter(**con) # 构造复杂(条件写死)
con = Q(Q(account=request.auth.user) & Q(status=0)) | Q(coupon__valid_begin_date__lte=ctime)
models.User.objects.filter(con) # 构造负责(条件动态)
q1 = Q()
q1.connector = 'OR'
for k,v in con.items():
q1.children.append((k,v,))
models.User.objects.filter(q1) 结算数据及目标:
payment_dict = {
'': {
course_id:2,
'title': 'CRM客户关系管理系统实战开发-专题',
'img': 'CRM.jpg', 'policy_id': '',
'coupon': {},
'default_coupon': 0,
'period': 210, 'period_display': '12个月', 'price': 122.0},
'': {
course_id:2,
'title': '爬虫开发-专题',
'img': '爬虫开发-专题.jpg',
'policy_id': '',
'coupon': {
4: {'coupon_type': 0, 'coupon_display': '立减券', 'money_equivalent_value': 40},
6: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 60, 'minimum_consume': 100}
},
'default_coupon': 0,
'period': 60,
'period_display': '2个月',
'price': 599.0}
} global_coupon_dict = {
'coupon': {
2: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 200, 'minimum_consume': 500}
},
'default_coupon': 0
}
========================================= redis ==============================================
redis = {
payment_1_2:{
course_id:2,
'title': 'CRM客户关系管理系统实战开发-专题',
'img': 'CRM.jpg', 'policy_id': '',
'coupon': {},
'default_coupon': 0,
'period': 210, 'period_display': '12个月', 'price': 122.0},
},
payment_1_1:{
course_id:1,
'title': '爬虫开发-专题',
'img': '爬虫开发-专题.jpg',
'policy_id': '',
'coupon': {
4: {'coupon_type': 0, 'coupon_display': '立减券', 'money_equivalent_value': 40},
6: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 60, 'minimum_consume': 100}
},
'default_coupon': 0,
'period': 60,
'period_display': '2个月',
'price': 599.0}
},
payment_global_coupon_1:{
'coupon': {
2: {'coupon_type': 1, 'coupon_display': '满减券', 'money_equivalent_value': 200, 'minimum_consume': 500}
},
'default_coupon': 0
}
}
11.15luffycity(7)的更多相关文章
- 地区sql
/*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...
- WinForm 天猫2013双11自动抢红包【源码下载】
1. 正确获取红包流程 2. 软件介绍 2.1 效果图: 2.2 功能介绍 2.2.1 账号登录 页面开始时,会载入这个网站:https://login.taobao.com/member/login ...
- C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)
#include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...
- CSS垂直居中的11种实现方式
今天是邓呆呆球衣退役的日子,在这个颇具纪念意义的日子里我写下自己的第一篇博客,还望前辈们多多提携,多多指教! 接下来,就进入正文,来说说关于垂直居中的事.(以下这11种垂直居中的实现方式均为笔者在日常 ...
- C++ 11 多线程--线程管理
说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...
- CSharpGL(11)用C#直接编写GLSL程序
CSharpGL(11)用C#直接编写GLSL程序 +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharp ...
- ABP(现代ASP.NET样板开发框架)系列之11、ABP领域层——仓储(Repositories)
点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之11.ABP领域层——仓储(Repositories) ABP是“ASP.NET Boilerplate Proj ...
- C++11 shared_ptr 智能指针 的使用,避免内存泄露
多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...
- C++11网络编程
Handy是一个简洁优雅的C++11网络库,适用于linux与Mac平台.十行代码即可完成一个完整的网络服务器. 下面是echo服务器的代码: #include <handy/handy.h&g ...
随机推荐
- poj3087 Shuffle'm Up(bfs)
http://poj.org/problem?id=3087 注意复制字符串的时候,要在末尾加上'\0',否则导致strcmp出错. 还有就是开数组大小的时候看清楚一点,别开错了debug了好久. # ...
- socket.io的websocket示例
写了一个简单的demo,直接上代码吧.用的时候注意一下版本号,可能 socket.io 的 API 有修改~ 效果图 index.html <!DOCTYPE <!DOCTYPE html ...
- springboot配置双数据源 MySQL和SqlServer
1. pom文件的驱动jar包加上去, compile 'com.microsoft.sqlserver:mssql-jdbc:6.2.2.jre8' 2. application.yml sprin ...
- nginx配置实例
user root root; worker_processes ; #error_log logs/error.log; #error_log logs/error.log notice; #err ...
- Java Lambda 表达式 对 Map 对象排序
Map<String,String> mailParams = new LinkedHashMap<>(); mailParams.put("Action" ...
- Java全栈程序员之07:IDEA中使用MAVEN构架生产级的Web项目
在上一篇我们介绍了如何在IDEA中使用MAVEN,以及如何创建依赖等.那么在这一篇中,我们就试图搭建一个生产级的解决方案,大家可以使用这个解决方案作为骨架代码来搭建自己的开发环境. 在这里,我们要完成 ...
- HIVE开发总结
基本数据类型 查看所有函数 搜索函数 搜索表 查看函数使用方法 关键字补全 显示表头 SET环境变量 查看建表语句.数据文件置 执行外部命令 NVL CONCAT IF CASE TRIM SUBST ...
- URL参数编码
简单明了区分escape.encodeURI和encodeURIComponent 一.前言讲这3个方法区别的文章太多了,但是大部分写的都很绕.本文试图从实践角度去讲这3个方法. 二.escape和它 ...
- 【Linux】关于ffmpeg的一些常见用法
一.FFmpeg简介 FFmpeg是一款非常快速的视频和音频转换器, 是开源项目 FFmpeg (Fast Forward moving pictures expert group) 的命令行程序. ...
- iOS- UITextView与键盘回收与键盘遮挡输入框
一.UITextView 可以实现多行输入的文本框,基本属性与UITextField相似,可以输入多行,可以滚动.UITextView还有个代理方式- (BOOL)textView:(UITextVi ...