Luffy:后端接口设计(django)
接口设计
一、登录认证接口
二、课程接口设计
分析:
课程和课程详情接口,是展示为主,为get请求,是通过serializer来实现的,
接口返回的数据结构中,展示的内容是通过serializer中的字段来确定的。
{ "code": 0, "data": [{ "id": 1, "name": "Python开发21天入门", "course_img": "https://luffycity.com/static/frontend/course/5/Python21天入门必备_1509095274.4902391.png", "brief": "Python 以其简洁、优雅、高效的特点,成为目前最流行的4大主流开发语言之一,其应用广泛,易学易用,让很多人爱不释手。本套课程为初学者量身打造,是你入门 Python 的必修课程。\\r\\nPS. 此课程特别适合之前完全无任何开发经验的小白白学习!知名网红讲师亲自肉身上阵,课程内容幽默风趣不枯燥,深入浅出,包君满意。", "level": "中级", "coursedetail_id": null, "is_free": false, "price": "¥0", "origin_price": null }, { "id": 2, "name": "Django框架学习", "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "brief": "Django是Python语言中最流行、最强大的WEB框架,可快速构建稳定强大的WEB项目,大大提高开发效率,很多知名项目都是基于Django开发,如Disqus、Pinterest、Instagram、Bitbucket等, Django官方Slogan是The framework for perfectionist with deadline! 一个为完美主义者且又开发工期很紧的人设计的框架,事实确实如此,Django自身集成了丰富的WEB开发通用组件,如用户认证、分页、中间件、缓存、session等,可以避免浪费大量时间重复造轮子。人生苦短,join the course now and start to build your first web program based on Django.", "level": "中级", "coursedetail_id": "1", "is_free": false, "price": "¥100.0", "origin_price": null }, { "id": 3, "name": "Git入门", "course_img": "https://luffycity.com/static/frontend/course/42/github_1528713275.7115595.jpeg", "brief": "Git是一个开源的分布式版本控制系统,可以有效、高速的处理从很小到非常大的项目版本管理,GitHub就是基于git作为唯一的版本库格式的一个面向开源及私有软件项目的托管平台,除了git代码仓库托管及基本的Web管理界面以外,还提供了订阅、讨论组、文本渲染、在线文件编辑器等功能。此课程将一步步带你熟悉git的使用以及如何将代码托管到GitHub平台以及日后工作与他人如何使用git进行协同开发。", "level": "中级", "coursedetail_id": null, "is_free": false, "price": "¥0", "origin_price": null }, { "id": 4, "name": "Linux系统基础5周入门精讲", "course_img": "https://luffycity.com/static/frontend/course/12/Linux5周入门_1509589530.6144893.png", "brief": "Linux世界上使用最多的系统之一,这位幕后英雄支持着各大网站的运行。\\r\\nLinux就像一个高冷的贵妇,你很难打动她。但是只要你打动她,她就对你死心塌地了。所以如何征服Linux这位贵妇,即Linux入门就很重要了。\\r\\n自学可能需要半年甚至更久,但观看我们这个专题课程五周让你熟练使用命令和常用服务以及排除常见故障。\\r\\nPS. 此课程特别适合之前完全无任何Linux使用或运维经验的小白白学习!知名网红讲师亲自肉身上阵,课程内容幽默风趣不枯燥,深入浅出,包君满意。", "level": "中级", "coursedetail_id": "2", "is_free": false, "price": "¥1000.0", "origin_price": null }] }
from api import models from api.utils import serializer from rest_framework.response import Response from rest_framework.viewsets import ModelViewSet from api.utils.auth import ExpiringTokenAuthentication from api.utils.filter import CourseFilter class CourseView(ModelViewSet): authentication_classes = [ExpiringTokenAuthentication,] queryset = models.Course.objects.all() serializer_class = serializer.CourseSerializer filter_backends = [CourseFilter,] def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) page = self.paginate_queryset(queryset) if page is not None: serializer = self.get_serializer(page, many=True) return self.get_paginated_response(serializer.data) serializer = self.get_serializer(queryset, many=True) return Response({"code": 0, "data": serializer.data}) class CourseDetailView(ModelViewSet): queryset = models.CourseDetail.objects.all() serializer_class = serializer.CourseDetailSerializer class CourseCategoryView(ModelViewSet): queryset = models.CourseCategory.objects.all() serializer_class = serializer.CourseCategorySerializer def list(self, request, *args, **kwargs): queryset = self.filter_queryset(self.get_queryset()) serializer = self.get_serializer(queryset, many=True) return Response({"error_no":0,"data":serializer.data})
from rest_framework import serializers from api import models class CourseCategorySerializer(serializers.ModelSerializer): class Meta: model = models.Course fields = ( "id", "name", ) class CourseSerializer(serializers.ModelSerializer): level = serializers.CharField(source="get_level_display") coursedetail_id=serializers.CharField(source="coursedetail.pk") class Meta: model = models.Course fields = ( 'id', 'name', 'course_img', 'brief', 'level', "coursedetail_id" ) def to_representation(self, instance): data = super(CourseSerializer, self).to_representation(instance) # 购买人数 # data["people_buy"] = instance.order_details.all().count() # 价格套餐列表 price_policies = instance.price_policy.all().order_by("price").only("price") price = getattr(price_policies.first(), "price", 0) if price_policies and price == 0: is_free = True price = "免费" origin_price = "原价¥{}".format(price_policies.last().price) else: is_free = False price = "¥{}".format(price) origin_price = None # 是否免费 data["is_free"] = is_free # 展示价格 data["price"] = price # 原价 data["origin_price"] = origin_price return data class CourseDetailSerializer(serializers.ModelSerializer): name=serializers.CharField(source="course.name") prices = serializers.SerializerMethodField() brief = serializers.StringRelatedField(source='course.brief') study_all_time = serializers.StringRelatedField(source='hours') level = serializers.CharField(source='course.get_level_display') teachers_info = serializers.SerializerMethodField() is_online = serializers.SerializerMethodField() recommend_coursesinfo = serializers.SerializerMethodField() # learnnumber = serializers.SerializerMethodField() # OftenAskedQuestion = serializers.SerializerMethodField() class Meta: model = models.CourseDetail fields="__all__" def get_prices(self, obj): return PricePolicySerializer( obj.course.price_policy.all(), many=True, context=self.context ).data def get_study_all_time(self, obj): return "30小时" def get_recommend_coursesinfo(self, obj): courses = RecommendCourseSerializer(obj.recommend_courses.all(), many=True) return courses.data def get_teachers_info(self, obj): teachers = TeacherSerializer(obj.teachers.all(), many=True) return teachers.data def get_is_online(self, obj): if obj.course.status == 0: return True elif obj.course.status == 2: return False else: return '' # def get_learnnumber(self, obj): # return obj.course.order_details.all().count() # def get_OftenAskedQuestion(self, obj): # question_queryset = models.OftenAskedQuestion.objects.filter(content_type__model='Course', # object_id=obj.course.id) # serializer = OftenAskedQuestionSerializer(question_queryset, many=True) # return serializer.data # class RecommendCourseSerializer(serializers.ModelSerializer): course_id = serializers.CharField(source="pk") course_name = serializers.CharField(source="name") class Meta: model = models.Course fields = ('course_id', 'course_name',) class PricePolicySerializer(serializers.ModelSerializer): valid_period_name = serializers.StringRelatedField(source="get_valid_period_display") class Meta: model = models.PricePolicy fields = ('id', 'valid_period', 'valid_period_name', 'price',) class CourseChapterSerializer(serializers.ModelSerializer): chapter_name = serializers.SerializerMethodField() chapter_symbol = serializers.SerializerMethodField() class Meta: model = models.CourseChapter fields = ( 'id', 'chapter_name', 'chapter_symbol', ) def get_chapter_name(self, instance): return '第%s章·%s' % (instance.chapter, instance.name) def get_chapter_symbol(self, instance): return "chapter_%s_%s" % (self.context.get('enrolled_course_id', 1), instance.id) def to_representation(self, instance): data = super(CourseChapterSerializer, self).to_representation(instance) queryset = instance.coursesections.all().order_by("order") # 获取章节对应的课时数量 data["section_of_count"] = queryset.count() data["free_trail"] = queryset.filter(free_trail=True).exists() data["coursesections"] = SectionSerializer( queryset, many=True, read_only=True, context=self.context ).data return data class OftenAskedQuestionSerializer(serializers.ModelSerializer): question_tittle = serializers.SerializerMethodField() question_answer = serializers.SerializerMethodField() class Meta: model = models.OftenAskedQuestion fields = ('question_tittle', 'question_answer') def get_question_tittle(self, obj): return obj.question def get_question_answer(self, obj): return obj.answer class TeacherSerializer(serializers.ModelSerializer): teacher_id = serializers.CharField(source="pk") teacher_name = serializers.CharField(source="name") teacher_brief = serializers.CharField(source="brief") teacher_image = serializers.CharField(source="image") class Meta: model = models.Teacher fields = ('teacher_id', 'teacher_name', 'title', 'signature', 'teacher_image', 'teacher_brief') class UserInfoSerializer(serializers.ModelSerializer): class Meta: model=models.UserInfo fields="__all__"
三、购物车接口
购物车接口包含加入购物车和显示购物车
1、加入购物车(post)
加入购物车主要是存入redis
是post请求,携带的数据如下:

- 获取课程相关数据
- 验证数据合法性
- 校验course_id是否合法,判断是否存在接口,用 .get()
- 校验价格策略是否合法,首先求出该课程的所有价格策略,判断传入id,是否在所求的价格策略里,存在则合法
- 写入redis缓存中
- key:shoppingcat_1_1,
# shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id)
- key:shoppingcat_1_1,
- post请求加入购物车主要是存入redis,只返回编码和信息,不需要返回数据
{"code":1000,"msg":"加入购物车成功!","data":null}
2、查看购物车 (get)
get请求
- 取到当前登录的 user_id
- 拼接购物车的key,# shopping_car_1_*
-
shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, "*") 匹配所有该用户的课程
-
- 根据key,从redis中获取所有加入购物车的课程
- 先模糊查询匹配出所有符合要求的key
- 循环所有key,然后得到每一个课程,存入到shopping_car_list中,
- 构建结构数据结构,作为data
- 最终将获取的购物车中的信息,传给前端 ,返回数据前前面
3、修改购物车价格策略(put)
- 获取前端传过来的course_id,以及price_policy_id
- 校验数据合法性
- 课程是否存在,价格策略是否合法
- 修改redis中的price_policy_id
- 修改后的信息写入redis中即可
4、删除购物车中的课程
- 获取前端传过来的course_id
- 判断课程 id 是否合法,判断该课程是否在redis中存储,首先要拼接key值,
- 删除 redis 中数据
购物车完整代码:
{ "code": 1000, "msg": "", "data": { "shopping_car_list": [{ "id": 2, "name": "Django框架学习", "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "relate_price_policy": { "1": { "prcie": 100.0, "valid_period": 7, "valid_period_text": "1周", "default": false }, "2": { "prcie": 200.0, "valid_period": 14, "valid_period_text": "2周", "default": false }, "3": { "prcie": 300.0, "valid_period": 30, "valid_period_text": "1个月", "default": true } }, "default_price": 300.0, "default_price_period": 30, "default_price_policy_id": 3 }], "total": 1 } }
from rest_framework.views import APIView from rest_framework.viewsets import ViewSetMixin, ModelViewSet from api.utils.response import BaseResponse from rest_framework.response import Response from api.models import Course, CourseDetail, PricePolicy from django.core.exceptions import ObjectDoesNotExist from api.utils.exceptions import CommonException # from django_redis import get_redis_connection from django.conf import settings from api.utils.auth import ExpiringTokenAuthentication import json from api.utils.permission import LoginUserPermission import redis REDIS_CONN = redis.Redis(decode_responses=True) class ShoppingCarView(APIView): """ 1030 加入购物车失败 """ authentication_classes = [ExpiringTokenAuthentication, ] def post(self, request): res = BaseResponse() try: # 1 获取前端传过来的course_id 以及price_policy_id user_id course_id = request.data.get("course_id", "") price_policy_id = request.data.get("price_policy_id", "") user_id = request.user.id # 2 验证数据的合法性 # 2.1 验证course_id是否合法 course_obj = Course.objects.get(pk=course_id) # 2.2 校验价格策略是否能合法 # 查找课程关联的价格策略 price_policy_list = course_obj.price_policy.all() price_policy_dict = {} for price_policy in price_policy_list: price_policy_dict[price_policy.pk] = { "prcie": price_policy.price, "valid_period": price_policy.valid_period, "valid_period_text": price_policy.get_valid_period_display(), "default": price_policy.pk == price_policy_id } if price_policy_id not in price_policy_dict: raise CommonException(1001, "价格策略异常!") # 3 构建我们想要的数据结构 # 价格策略对象 pp = PricePolicy.objects.get(pk=price_policy_id) course_info = { "id": course_id, "name": course_obj.name, "course_img": course_obj.course_img, "relate_price_policy": price_policy_dict, "default_price": pp.price, "default_price_period": pp.valid_period, "default_price_policy_id": pp.pk } # 4 写入redis # 4.1 先拼接购物车的key shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) # 4.2 写入redis REDIS_CONN.set(shopping_car_key, json.dumps(course_info)) res.msg = "加入购物车成功!" except CommonException as e: res.code = e.code res.error = e.error except Exception as e: res.code = 1030 res.error = "加入购物车失败!" return Response(res.dict) def get(self, request): res = BaseResponse() try: # 1 取到user_id user_id = request.user.id # 2 拼接购物车的key shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, "*") print("shopping_car_key",shopping_car_key) # shopping_car_1_* # shopping_car_1_asdgnlaksdj # 3 去redis读取该用户的所有加入购物车的课程 # 3.1 先去模糊匹配出所有符合要求的key all_keys = REDIS_CONN.keys(shopping_car_key) print("all_keys",all_keys) # 3.2 循环所有的keys 得到每个可以 shopping_car_list = [] for key in all_keys: print("key",key) course_info = json.loads(REDIS_CONN.get(key)) shopping_car_list.append(course_info) res.data = {"shopping_car_list": shopping_car_list, "total": len(shopping_car_list)} except Exception as e: res.code = 1033 res.error = "获取购物车失败" print("res.dict",res.dict) return Response(res.dict) def put(self, request): res = BaseResponse() try: # 1 获取前端传过来的course_id 以及price_policy_id course_id = request.data.get("course_id", "") price_policy_id = request.data.get("price_policy_id", "") user_id = request.user.id # 2 校验数据的合法性 # 2.1 校验course_id是否合法 shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) if not REDIS_CONN.exists(shopping_car_key): res.code = 1035 res.error = "课程不存在" return Response(res.dict) # 2.2 判断价格策略是否合法 course_info = REDIS_CONN.hgetall(shopping_car_key) price_policy_dict = json.loads(course_info["price_policy_dict"]) if str(price_policy_id) not in price_policy_dict: res.code = 1036 res.error = "所选的价格策略不存在" return Response(res.dict) # 3 修改redis中的default_policy_id course_info["default_policy_id"] = price_policy_id # 4 修改信息后写入redis REDIS_CONN.hmset(shopping_car_key, course_info) res.data = "更新成功" except Exception as e: res.code = 1034 res.error = "更新价格策略失败" return Response(res.dict) def delete(self, request): res = BaseResponse() try: # 获取前端传过来的course_id course_id = request.data.get("course_id", "") user_id = request.user.id # 判断课程id是否合法 shopping_car_key = settings.SHOPPING_CAR_KEY % (user_id, course_id) if not REDIS_CONN.exists(shopping_car_key): res.code = 1039 res.error = "删除的课程不存在" return Response(res.dict) # 删除redis中的数据 REDIS_CONN.delete(shopping_car_key) res.data = "删除成功" except Exception as e: res.code = 1037 res.error = "删除失败" return Response(res.dict) ''' 1 post接口构建数据结构: { "id": 2, "default_price_period": 14, "relate_price_policy": { "1": { "valid_period": 7, "valid_period_text": "1周", "default": false, "prcie": 100.0 }, "2": { "valid_period": 14, "valid_period_text": "2周", "default": true, "prcie": 200.0 }, "3": { "valid_period": 30, "valid_period_text": "1个月", "default": false, "prcie": 300.0 } }, "name": "Django框架学习", "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "default_price": 200.0 } 2 get接口查询数据结构: { "data": { "total": 2, "shopping_car_list": [ { "id": 2, "default_price_period": 14, "relate_price_policy": { "1": { "valid_period": 7, "valid_period_text": "1周", "default": false, "prcie": 100 }, "2": { "valid_period": 14, "valid_period_text": "2周", "default": true, "prcie": 200 }, "3": { "valid_period": 30, "valid_period_text": "1个月", "default": false, "prcie": 300 } }, "name": "Django框架学习", "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "default_price": 200 }, { "id": 4, "default_price_period": 30, "relate_price_policy": { "4": { "valid_period": 30, "valid_period_text": "1个月", "default": true, "prcie": 1000 }, "5": { "valid_period": 60, "valid_period_text": "2个月", "default": false, "prcie": 1500 } }, "name": "Linux系统基础5周入门精讲", "course_img": "https://luffycity.com/static/frontend/course/12/Linux5周入门_1509589530.6144893.png", "default_price": 1000 } ] }, "code": 1000, "msg": "" } '''
四、结算接口
account
1、去结算(post)
点击去结算按钮,发送post请求,前台发送的数据为:
course_list = [{ "course_id": 1, "price_policy_id": 2 }, ]
- 获取数据
- 创建数据结构,先判断 redis 中是否存在 key 值,先清空,
找到所有以account_userid_*,全部清空
- 校验课程是否存在,查找关联的价格策略,将课程信息加入到每一个课程结算字典中
- 课程价格加入到价格列表中
- 查询当前用户拥有未使用的,在有效期的且与当前课程相关的优惠券
- 存储结算信息
- 获取通用优惠券,加入redis中
返回
{"code":1000,"msg":"","data":null}
2、展示结算页面(get)
- 取到user_id
- 拼接购物车 key
# shopping_car_1_*
# shopping_car_1_asdgnlaksdj - 去redis读取该用户的所有加入购物车的课程,
- 先去模糊匹配出所有符合要求的key
- 循环所有的keys 从redis中得到每个课程
返回
3、修改结算中的价格策略(put)
结算完整代码:
{ "code": 1000, "msg": "", "data": { "account_course_list": [{ "id": 2, "name": "Django框架学习", "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "relate_price_policy": { "1": { "prcie": 100.0, "valid_period": 7, "valid_period_text": "1周", "default": false }, "2": { "prcie": 200.0, "valid_period": 14, "valid_period_text": "2周", "default": false }, "3": { "prcie": 300.0, "valid_period": 30, "valid_period_text": "1个月", "default": true } }, "default_price": 300.0, "rebate_price": 300.0, "default_price_period": 30, "default_price_policy_id": 3, "coupon_list": [{ "pk": 3, "name": "清明节活动", "coupon_type": "折扣券", "money_equivalent_value": 0.0, "off_percent": 80, "minimum_consume": 0 }] }], "total": 1, "global_coupons": [{ "pk": 2, "name": "国庆节活动通用券", "coupon_type": "满减券", "money_equivalent_value": 50.0, "off_percent": null, "minimum_consume": 100 }], "total_price": "300.0" } }
from rest_framework.views import APIView from api.utils.response import BaseResponse from api.utils.auth import ExpiringTokenAuthentication from rest_framework.response import Response import json import datetime from django.conf import settings from api.models import Coupon, CouponRecord,Course,PricePolicy # from django_redis import get_redis_connection from api.utils.exceptions import CommonException from django.core.exceptions import ObjectDoesNotExist import redis REDIS_CONN = redis.Redis(decode_responses=True) class AccountView(APIView): ''' 结算接口 ''' authentication_classes = [ExpiringTokenAuthentication, ] def get_coupon_list(self, request, course_id=None): now = datetime.datetime.utcnow() coupon_record_list = CouponRecord.objects.filter( account=request.user, status=0, coupon__valid_begin_date__lte=now, coupon__valid_end_date__gt=now, coupon__content_type_id=14, coupon__object_id=course_id ) coupon_list = [] for coupon_record in coupon_record_list: coupon_list.append({ "pk": coupon_record.pk, "name": coupon_record.coupon.name, "coupon_type": coupon_record.coupon.get_coupon_type_display(), "money_equivalent_value": coupon_record.coupon.money_equivalent_value, "off_percent": coupon_record.coupon.off_percent, "minimum_consume": coupon_record.coupon.minimum_consume, }) return coupon_list def post(self, request, *args, **kwargs): # 1 获取数据 ''' course_list=[{ "course_id":1, "price_policy_id":2 }, ] :param request: :param args: :param kwargs: :return: ''' user = request.user course_list = request.data print("course_list",course_list) print("course_list",type(course_list)) response = BaseResponse() try: # 2 创建数据结构 # 清空操作 # 找到所有以account_userid_*,全部清空 del_list = REDIS_CONN.keys(settings.ACCOUNT_KEY % (user.pk, "*")) if del_list: REDIS_CONN.delete(*del_list) price_list=[] for course_dict in course_list: course_id=course_dict.get("course_id") price_policy_id=course_dict.get("price_policy_id") # 校验课程是否存在 course_obj=Course.objects.get(pk=course_id) # 查找课程关联的价格策略 price_policy_list = course_obj.price_policy.all() price_policy_dict = {} for price_policy in price_policy_list: price_policy_dict[price_policy.pk] = { "prcie": price_policy.price, "valid_period": price_policy.valid_period, "valid_period_text": price_policy.get_valid_period_display(), "default": price_policy.pk == price_policy_id } if price_policy_id not in price_policy_dict: raise CommonException(1001, "价格策略异常!") pp=PricePolicy.objects.get(pk=price_policy_id) # 将课程信息加入到每一个课程结算字典中 account_dict = { "id": course_id, "name": course_obj.name, "course_img": course_obj.course_img, "relate_price_policy": price_policy_dict, "default_price": pp.price, "rebate_price": pp.price, "default_price_period": pp.valid_period, "default_price_policy_id": pp.pk } # 课程价格加入到价格列表 price_list.append(float(pp.price)) # 查询当前用户拥有未使用的,在有效期的且与当前课程相关的优惠券 account_dict["coupon_list"] = self.get_coupon_list(request, course_id) # 存储结算信息 account_key = settings.ACCOUNT_KEY % (user.pk, course_id) REDIS_CONN.set(account_key, json.dumps(account_dict)) # 获取通用优惠券,加入redis中 REDIS_CONN.set("global_coupon_%s" % user.pk, json.dumps(self.get_coupon_list(request))) REDIS_CONN.set("total_price",sum(price_list)) except ObjectDoesNotExist as e: response.code = 1001 response.error = "课程不存在!" except CommonException as e: response.code = e.code response.error = e.error # except Exception as e: # response.code = 500 # response.error = str(e) return Response(response.dict) def get(self, request, *args, **kwargs): res = BaseResponse() try: # 1 取到user_id user_id = request.user.id # 2 拼接购物车的key account_key = settings.ACCOUNT_KEY % (user_id, "*") # shopping_car_1_* # shopping_car_1_asdgnlaksdj # 3 去redis读取该用户的所有加入购物车的课程 # 3.1 先去模糊匹配出所有符合要求的key all_keys = REDIS_CONN.scan_iter(account_key) # 3.2 循环所有的keys 得到每个课程 account_course_list = [] for key in all_keys: account_course = json.loads(REDIS_CONN.get(key)) account_course_list.append(account_course) global_coupons = json.loads(REDIS_CONN.get("global_coupon_%s" % request.user.pk)) total_price = REDIS_CONN.get("total_price") res.data = { "account_course_list": account_course_list, "total": len(account_course_list), "global_coupons": global_coupons, "total_price": total_price } except Exception as e: res.code = 1033 res.error = "获取购物车失败" return Response(res.dict) def cal_coupon_price(self,price,coupon_info): print("coupon_info",coupon_info) coupon_type=coupon_info["coupon_type"] money_equivalent_value=coupon_info.get("money_equivalent_value") off_percent=coupon_info.get("off_percent") minimum_consume=coupon_info.get("minimum_consume") rebate_price=0 if coupon_type == "立减券": # 立减券 rebate_price=price-money_equivalent_value if rebate_price <= 0: rebate_price=0 elif coupon_type == "满减券": # 满减券 if minimum_consume > price: raise CommonException(3000,"优惠券未达到最低消费") else: rebate_price=price-money_equivalent_value elif coupon_type == "折扣券": rebate_price=price*off_percent/100 return rebate_price def put(self,request, *args, **kwargs): ''' choose_coupons: { choose_coupons={"1":2,"2":3,"global_coupon_id":5} is_beli:true } ''' res=BaseResponse() # try: # 1 获取数据 choose_coupons=request.data.get("choose_coupons") is_beli=request.data.get("is_beli") user_pk=request.user.pk # 2 获取结算课程列表 cal_price={} data=self.get(request).data.get("data") account_course_list=data.get("account_course_list") print("account_course_list",account_course_list) ''' account_course_list=[{ 'id': 4, 'coupon_list': [{ 'off_percent': None, 'pk': 4, 'money_equivalent_value': 300.0, 'coupon_type': '立减券', 'minimum_consume': 0, 'name': '51劳动节' }], 'course_img': 'https://luffycity.com/static/frontend/course/12/Linux5周入门_1509589530.6144893.png', 'default_price': 1500.0, 'default_price_period': 60, 'relate_price_policy': { '5': { 'valid_period_text': '2个月', 'default': True, 'valid_period': 60, 'prcie': 1500.0 }, '4': { 'valid_period_text': '1个月', 'default': False, 'valid_period': 30, 'prcie': 1000.0 } }, 'default_price_policy_id': 5, 'name': 'Linux系统基础5周入门精讲' }, { 'id': 2, 'coupon_list': [{ 'off_percent': 80, 'pk': 3, 'money_equivalent_value': 0.0, 'coupon_type': '折扣券', 'minimum_consume': 0, 'name': '清明节活动' }], 'course_img': 'https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png', 'default_price': 300.0, 'default_price_period': 30, 'relate_price_policy': { '3': { 'valid_period_text': '1个月', 'default': True, 'valid_period': 30, 'prcie': 300.0 }, '1': { 'valid_period_text': '1周', 'default': False, 'valid_period': 7, 'prcie': 100.0 }, '2': { 'valid_period_text': '2周', 'default': False, 'valid_period': 14, 'prcie': 200.0 } }, 'default_price_policy_id': 3, 'name': 'Django框架学习' }] ''' account_courses_info={} for account_course in account_course_list: temp={ "coupon":{}, "default_price":account_course["default_price"] } account_courses_info[account_course["id"]]=temp for item in account_course["coupon_list"]: print("choose_coupons",choose_coupons) # {'4': 4} print(str(account_course["id"])) coupon_id=choose_coupons.get(str(account_course["id"])) if coupon_id == item["pk"]: temp["coupon"]=item print("account_course_info",account_courses_info) price_list=[] total_price=0 ''' { 2: { 'coupon': { 'money_equivalent_value': 0.0, 'name': '清明节活动', 'pk': 3, 'off_percent': 80, 'coupon_type': '折扣券', 'minimum_consume': 0 }, 'default_price': 200.0 } } ''' for key,val in account_courses_info.items(): if not val.get("coupon"): price_list.append(val["default_price"]) cal_price[key]=val["default_price"] else: coupon_info=val.get("coupon") default_price=val["default_price"] rebate_price=self.cal_coupon_price(default_price,coupon_info) price_list.append(rebate_price) cal_price[key]=rebate_price print("课程优惠券后价格列表price_list",price_list) total_price=sum(price_list) # 3 计算通用优惠券的价格 global_coupon_id=choose_coupons.get("global_coupon_id") if global_coupon_id: global_coupons=data.get("global_coupons") print("global_coupons",global_coupons) global_coupon_dict={} for item in global_coupons: global_coupon_dict[item["pk"]]=item total_price=self.cal_coupon_price(total_price,global_coupon_dict[global_coupon_id]) print("通用优惠券",global_coupon_dict[global_coupon_id]["coupon_type"]) print("计算后total_price=",total_price) # 计算贝里 if json.loads(is_beli): print("request.user.beli",request.user.beli) total_price=total_price-request.user.beli/10 if total_price<0: total_price=0 print("贝里数计算后",total_price) cal_price["total_price"]=total_price res.data=cal_price # except Exception as e: # res.code=500 # res.msg="结算错误!"+str(e) return Response(res.dict) ''' 1 结算中心post添加接口数据结构: { "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "coupon_list": [{ "name": "清明节活动", "minimum_consume": 0, "money_equivalent_value": 0.0, "off_percent": 80, "pk": 3, "coupon_type": "折扣券" }], "relate_price_policy": { "1": { "valid_period": 7, "valid_period_text": "1周", "prcie": 100.0, "default": true }, "2": { "valid_period": 14, "valid_period_text": "2周", "prcie": 200.0, "default": false }, "3": { "valid_period": 30, "valid_period_text": "1个月", "prcie": 300.0, "default": false } }, "name": "Django框架学习", "default_price": 100.0, "id": 2, "default_price_period": 7, "default_price_policy_id": 1 } 2 结算中心get查询接口: { "data": { "total": 1, "global_coupons": [ { "name": "国庆节活动通用券", "coupon_type": "满减券", "minimum_consume": 100, "money_equivalent_value": 50, "off_percent": null, "pk": 2 } ], "total_price": "100.0", "account_course_list": [ { "course_img": "https://luffycity.com/static/frontend/course/3/Django框架学习_1509095212.759272.png", "name": "Django框架学习", "relate_price_policy": { "1": { "valid_period": 7, "prcie": 100, "valid_period_text": "1周", "default": true }, "2": { "valid_period": 14, "prcie": 200, "valid_period_text": "2周", "default": false }, "3": { "valid_period": 30, "prcie": 300, "valid_period_text": "1个月", "default": false } }, "coupon_list": [ { "name": "清明节活动", "coupon_type": "折扣券", "minimum_consume": 0, "money_equivalent_value": 0, "off_percent": 80, "pk": 3 } ], "default_price": 100, "id": 2, "default_price_period": 7, "default_price_policy_id": 1 } ] }, "code": 1000, "msg": "" } '''
五、支付接口
payment
六、订单接口
order

浙公网安备 33010602011771号