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)的更多相关文章

  1. 地区sql

    /*Navicat MySQL Data Transfer Source Server : localhostSource Server Version : 50136Source Host : lo ...

  2. WinForm 天猫2013双11自动抢红包【源码下载】

    1. 正确获取红包流程 2. 软件介绍 2.1 效果图: 2.2 功能介绍 2.2.1 账号登录 页面开始时,会载入这个网站:https://login.taobao.com/member/login ...

  3. C++11特性——变量部分(using类型别名、constexpr常量表达式、auto类型推断、nullptr空指针等)

    #include <iostream> using namespace std; int main() { using cullptr = const unsigned long long ...

  4. CSS垂直居中的11种实现方式

    今天是邓呆呆球衣退役的日子,在这个颇具纪念意义的日子里我写下自己的第一篇博客,还望前辈们多多提携,多多指教! 接下来,就进入正文,来说说关于垂直居中的事.(以下这11种垂直居中的实现方式均为笔者在日常 ...

  5. C++ 11 多线程--线程管理

    说到多线程编程,那么就不得不提并行和并发,多线程是实现并发(并行)的一种手段.并行是指两个或多个独立的操作同时进行.注意这里是同时进行,区别于并发,在一个时间段内执行多个操作.在单核时代,多个线程是并 ...

  6. CSharpGL(11)用C#直接编写GLSL程序

    CSharpGL(11)用C#直接编写GLSL程序 +BIT祝威+悄悄在此留下版了个权的信息说: 2016-08-13 由于CSharpGL一直在更新,现在这个教程已经不适用最新的代码了.CSharp ...

  7. ABP(现代ASP.NET样板开发框架)系列之11、ABP领域层——仓储(Repositories)

    点这里进入ABP系列文章总目录 基于DDD的现代ASP.NET开发框架--ABP系列之11.ABP领域层——仓储(Repositories) ABP是“ASP.NET Boilerplate Proj ...

  8. C++11 shared_ptr 智能指针 的使用,避免内存泄露

    多线程程序经常会遇到在某个线程A创建了一个对象,这个对象需要在线程B使用, 在没有shared_ptr时,因为线程A,B结束时间不确定,即在A或B线程先释放这个对象都有可能造成另一个线程崩溃, 所以为 ...

  9. C++11网络编程

    Handy是一个简洁优雅的C++11网络库,适用于linux与Mac平台.十行代码即可完成一个完整的网络服务器. 下面是echo服务器的代码: #include <handy/handy.h&g ...

随机推荐

  1. poj3087 Shuffle'm Up(bfs)

    http://poj.org/problem?id=3087 注意复制字符串的时候,要在末尾加上'\0',否则导致strcmp出错. 还有就是开数组大小的时候看清楚一点,别开错了debug了好久. # ...

  2. socket.io的websocket示例

    写了一个简单的demo,直接上代码吧.用的时候注意一下版本号,可能 socket.io 的 API 有修改~ 效果图 index.html <!DOCTYPE <!DOCTYPE html ...

  3. springboot配置双数据源 MySQL和SqlServer

    1. pom文件的驱动jar包加上去, compile 'com.microsoft.sqlserver:mssql-jdbc:6.2.2.jre8' 2. application.yml sprin ...

  4. nginx配置实例

    user root root; worker_processes ; #error_log logs/error.log; #error_log logs/error.log notice; #err ...

  5. Java Lambda 表达式 对 Map 对象排序

    Map<String,String> mailParams = new LinkedHashMap<>(); mailParams.put("Action" ...

  6. Java全栈程序员之07:IDEA中使用MAVEN构架生产级的Web项目

    在上一篇我们介绍了如何在IDEA中使用MAVEN,以及如何创建依赖等.那么在这一篇中,我们就试图搭建一个生产级的解决方案,大家可以使用这个解决方案作为骨架代码来搭建自己的开发环境. 在这里,我们要完成 ...

  7. HIVE开发总结

    基本数据类型 查看所有函数 搜索函数 搜索表 查看函数使用方法 关键字补全 显示表头 SET环境变量 查看建表语句.数据文件置 执行外部命令 NVL CONCAT IF CASE TRIM SUBST ...

  8. URL参数编码

    简单明了区分escape.encodeURI和encodeURIComponent 一.前言讲这3个方法区别的文章太多了,但是大部分写的都很绕.本文试图从实践角度去讲这3个方法. 二.escape和它 ...

  9. 【Linux】关于ffmpeg的一些常见用法

    一.FFmpeg简介 FFmpeg是一款非常快速的视频和音频转换器, 是开源项目 FFmpeg (Fast Forward moving pictures expert group) 的命令行程序. ...

  10. iOS- UITextView与键盘回收与键盘遮挡输入框

    一.UITextView 可以实现多行输入的文本框,基本属性与UITextField相似,可以输入多行,可以滚动.UITextView还有个代理方式- (BOOL)textView:(UITextVi ...