• python 全栈开发,Day106(结算中心(详细),立即支付)


    昨日内容回顾

    1. 为什么要开发路飞学城?
        提供在线教育的学成率;
        特色:
            学,看视频,单独录制增加趣味性。
            练,练习题
            改,改学生代码
            管,管理
            测,阶段考核
                线下:8次留级考试
                
    2. 组织架构
        - 开发
            - 后端
            - 前端
        - 测试
        - UI
        - 产品经理
        - 运维
        - 销售
        - 运营
        - 全职导师
        - 行政
        - 财务
        
    3. 项目架构
        - 主站
            - nginx + uwsgi + django 
        - 导师后台
        - 管理后台
        
    4. 开发周期和人数
        2017-07:开始做
        2017-11:第一版上线
        2018-02:功能完善和迭代
        2018-03:题库系统/wiki
        
    5. 前后端分离
        vue.js
        restful api 
        
    6. 跨域相关
        正式:无
        测试:有跨域,使用CORS解决;
            - 简单请求
            - 复杂请求
                
    7. 你负责项目中的什么?
        课程
        购物车
        深科技
            15个接口
    View Code

    一、结算中心(详细)

    完整代码

    先来看payment.py完整代码

    import json
    import redis
    from django.conf import settings
    from rest_framework.views import APIView
    from rest_framework.viewsets import ViewSetMixin
    from rest_framework.response import Response
    from api.utils.auth import LuffyAuthentication
    from api import models
    from api.utils.response import BaseResponse
    
    # CONN = redis.Redis(host='192.168.11.61',port=6379)
    from django_redis import get_redis_connection
    CONN = get_redis_connection("default")
    
    
    class CourseNotExistsException(Exception):
        def __init__(self,msg):
            self.msg = msg
    
    class PaymentView(ViewSetMixin,APIView):
    
        authentication_classes = [LuffyAuthentication,]
    
        def create(self,request,*args,**kwargs):
            """
            在结算中添加课程
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            response = BaseResponse()
            try:
                # 1.接受用户选择的要结算的课程ID列表
                userid = request.user.id
                # [1,3,55]
                courseid_list = request.data.get('courseid')  # 拿到的是一个列表
    
                # 2.清空当前用户request.user.id结算中心的数据
                pattern = 'payment_%s_%s' % (userid, '*')
                # 方式一:
                key_list = CONN.keys(pattern)
                CONN.delete(*key_list)
                # 方式二:
                # for key in CONN.keys(pattern):
                #     CONN.delete(key)  # 清空结算中心
    
                # 3.循环要加入结算中的所有课程ID列表
    
                import datetime
                today = datetime.date.today()
    
                for course_id in courseid_list:
                    shop_car_key = "shopping_car_%s_%s" %(userid,course_id)
    
                    # 3.1 判断购物车中是否存在此key
                    if not CONN.exists(shop_car_key):
                        raise CourseNotExistsException('购物车中不存在该课程')
    
                    # 3.2 去购物车中获取课程信息
                    id = CONN.hget(shop_car_key, 'id').decode('utf-8')
                    name = CONN.hget(shop_car_key, 'name').decode('utf-8')
                    img = CONN.hget(shop_car_key, 'img').decode('utf-8')
                    default_price_id = CONN.hget(shop_car_key, 'default_price_id').decode('utf-8')
                    price_policy_dict = json.loads(CONN.hget(shop_car_key, 'price_policy_dict').decode('utf-8'))
                    price_policy = price_policy_dict[default_price_id]
                    """
                    {
                        'id':1,
                        'price':99.99,
                        'valid_period':60,
                        'valid_period_display':2个月
                    }
                    """
    
                    # 3.3 根据课程ID获取该课程可用的优惠券
    
                    coupon_list = models.CouponRecord.objects.filter(account_id=userid,
                                                           status=0,
                                                           coupon__valid_begin_date__lte=today,
                                                           coupon__valid_end_date__gte=today,
                                                           coupon__object_id=course_id,
                                                           coupon__content_type__model='course'
                                                           )
                    # 加入结算中心
    
                """
                for course_id in 用户提交课程ID列表:
                    3.1 根据course_id,request.user.id去购物车中获取商品信息:商品名称、图片、价格(id,周期,显示周期,价格)
                    3.2 根据course_id,request.user.id获取 
                            - 当前用户
                            - 当前课程
                            - 可用的优惠券
                    
                    加入结算中心
                    
                    提示:可以使用contenttypes
                """
    
                # 4.获取当前用户所有未绑定课程优惠券
                #       - 未使用
                #       - 有效期内
                #       - 加入结算中心:glocal_coupon_用户ID
    
                global_coupon_list = models.CouponRecord.objects.filter(account_id=userid,
                                                   status=0,
                                                   coupon__valid_begin_date__lte=today,
                                                   coupon__valid_end_date__gte=today,
                                                   coupon__content_type__isnull=True
                                                   )
                # 加入到结算中心
            except CourseNotExistsException as e:
                response.code = 1010
                response.error = e.msg
    
            except Exception as e:
                pass
    
            return Response('...')
    
    
        def list(self,request,*args,**kwargs):
            """
            查看结算中心
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
    
            # 1. 根据用户ID去结算中心获取该用户所有要结算课程
    
            # 2. 根据用户ID去结算中心获取该用户所有可用未绑定课程的优惠券
    
            # 3. 用户表中获取贝里余额
    
            # 4. 以上数据构造成一个字典
            return Response('...')
    
    
        def update(self,request,*args,**kwargs):
            """
            更新优惠券
            :param request:
            :param args:
            :param kwargs:
            :return:
            """
            # 1. 获取用户提交:
            #       course_id=1,coupon_id=3
            #       course_id=0,coupon_id=6
    
            # 2. course_id=1 --> 去结算中心获取当前用户所拥有的绑定当前课程优惠,并进行校验
            #       - 成功:defaul_coupon_id=3
            #       - 否则:非法请求
    
            # 2. course_id=0 --> 去结算中心获取当前用户所拥有的未绑定课程优惠,并进行校验
            #       - 成功:defaul_coupon_id=3
            #       - 否则:非法请求
    View Code

    代码解释

    1

    接收用户选择的要结算的课程ID列表

    userid = request.user.id

    当用户认证成功后,request.user就是一个Account表的一个对象。所以request.user.id就能取到用户id。至于为什么request.user就是一个Account表的一个对象,请参考DRF认证源码解析

    2

    清空当前用户request.user.id结算中心的数据

    结算中心的数据在redis中,它的键值为payment_用户id_课程id。由于redis存储的是key-value,所以清空就是删除!

    查询当前用户的结算中心,使用模糊匹配

    pattern = 'payment_%s_%s' % (userid, '*')

    删除有2种方式:

    方式一:

    key_list = CONN.keys(pattern)
    CONN.delete(*key_list)

    方式二:

    for key in CONN.keys(pattern):
        CONN.delete(key)

    推荐使用方式一,*key_list表示打散,再将每一个值分别传给CONN.delete

    3

    循环要加入结算中的所有课程ID列表

    结算中心的数据,是来源于购物车,由于购物车数据在redis中,直接查询就可以了

    for course_id in courseid_list:
        shop_car_key = "shopping_car_%s_%s" %(userid,course_id)

    前端传给后端的课程是一个列表,它是使用html的复选框,默认数据类型为列表。所以需要使用for循环

    购物车的键值为shopping_car_用户id_课程id,它的数据结构如下:

    购物车 = {
        'shopping_car_用户id_课程id':{
            id:'课程id',
            name:'课程名'
            img:'课程图片'
            default_price_id:'默认价格策略id',
            # 所有价格策略
            price_policy_dict = {
                '价格策略id':{
                    'id':价格策略id,
                    'price':'原价',
                    'valid_period':'有效期',
                    'valid_period_display':'有效期中文显示'
                }
            }
        },
    }

    注意:下面展示的部分代码是在for循环中的

    3.1 判断购物车中是否存在此key

    if not CONN.exists(shop_car_key):
        raise CourseNotExistsException('购物车中不存在该课程')

    CourseNotExistsException是自定义的一个方法,用来做自定义的异常。

    raise 表示主动抛出异常,那么下面的代码,将不会执行!也不会被Exception捕获到!

    这里为什么要判断购物车课程是否存在呢?如果是正常用户,当然不会有问题。但如果是爬虫用户,它可以伪造数据,发给后端服务器。所以这里要判断数据的真实性!

    3.2 去购物车中获取课程信息

    下面的代码,分别获取课程id,课程名,课程图片,默认价格策略id,所有价格策略,当前课程价格策略。

    id = CONN.hget(shop_car_key, 'id').decode('utf-8')
    name = CONN.hget(shop_car_key, 'name').decode('utf-8')
    img = CONN.hget(shop_car_key, 'img').decode('utf-8')
    default_price_id = CONN.hget(shop_car_key, 'default_price_id').decode('utf-8')
    price_policy_dict = json.loads(CONN.hget(shop_car_key, 'price_policy_dict').decode('utf-8'))
    price_policy = price_policy_dict[default_price_id]

    价格策略说明:有些课程有3个价格策略,比如1周,1个月,3个月。那么用户选择一个价格策略后,点击加入购物车之后。这个默认价格策略id,就是用户选择的。通过这个,就可以从所有的价格策略中,取出当前价格策略的相关信息。

    price_policy应该是这个样子

    {
        'id':1,
        'price':99,
        'valid_period':60,
        'valid_period_display':1个月
    }

    上面之所以,取出这么多数据,是为了得到这个效果:

    3.3 根据课程ID获取该课程可用的优惠券

    需要从CouponRecord,它是优惠券发放、消费纪录表。从这个表中,取出相关信息!

    先来看完整的ORM查询语句

    coupon_list = models.CouponRecord.objects.filter(account_id=userid,
                                                           status=0,
                                                           coupon__valid_begin_date__lte=today,
                                                           coupon__valid_end_date__gte=today,
                                                           coupon__object_id=course_id,
                                                           coupon__content_type__model='course'
                                                           )

    再来对一个条件,做具体分析!

    account_id=userid 表示用户id等于当前登录用户id。通俗来讲,就是谁领用的优惠券!

    status=0 表示优惠券状态为:未使用。当用户结算时,使用了优惠券,并付款成功后。这个优惠券的状态,应该要改成已使用。

    重点来了,优惠券是有时间限制的。如何判断优惠券是否过期?

    根据当前时间来判断!举例:

    import datetime
    #比较大小
    today = datetime.date.today().strftime("%Y-%m-%d")  # 当前日期
    start_time= "2017-01-04"  # 开始时间
    
    print("%s大于等于%s:"%(today,start_time),today>=start_time)

    执行输出:

    2018-08-16大于2017-01-04: True

    那么在ORM中,也是这么比较的。大于使用gte,小于使用lte

    由于Course和coupon表做了content_type关联。

    所以coupon__content_type__model='course' 表示django_content_type表中的model字段的值为course,也就表示course表

    coupon__object_id=course_id  表示course表的主键id。

    那么这2句,就可以查询到优惠券具体绑定到课哪个课程了!

    二、立即支付

    点击立即支付,就会跳转到支付宝支付,那么在这个过程中,经历了怎样的步骤呢?

    伪代码

    在views目录中,创建文件order.py,伪代码如下:

    import json
    import redis
    from django.conf import settings
    from rest_framework.views import APIView
    from rest_framework.viewsets import ViewSetMixin
    from rest_framework.response import Response
    from api.utils.auth import LuffyAuthentication
    from api import models
    from api.utils.response import BaseResponse
    
    # CONN = redis.Redis(host='192.168.11.61',port=6379)
    from django_redis import get_redis_connection
    CONN = get_redis_connection("default")
    
    """
    {
        payment_2_1:{
            id:1,
            name:'Python基础',
            img:'xxx',
            price:99.99,
            period:90,
            period_display:3个月,
            default_coupon_id:0,
            coupon_dict:{
                '1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
            }
        },
        payment_2_3:{
            id:2,
            name:'Python进阶',
            img:'xxx',
            price:99.99,
            period:90,
            period_display:3个月,
            default_coupon_id:0,
            coupon_dict:{
                '1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
            }
        },
        global_coupon_2:{
            '1':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '2':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
                '3':{'type':0,'text':'立减','money_equivalent_value':'xx','off_percent':'xx','minimum_consume'},
        }
    }
    
    
    """
    
    class OrderView(ViewSetMixin,APIView):
        authentication_classes = [LuffyAuthentication, ]
    
    
        def create(self,request,*args,**kwargs):
            """
            立即支付
            :param args:
            :param kwargs:
            :return:
            """
            response = BaseResponse()
    
            try:
                # 1. 接收用户发送的数据
                """
                {'balance':1000,'alipay':228 }
                """
                balance = request.data.get('balance')
                alipay = request.data.get('alipay')
    
                # 2. 检验贝里余额是否够用
                if request.user.balance < balance:
                    raise Exception('贝里余额不足')
    
                # 3.获取结算中心的每个课程信息并应用优惠券
                """
                    3.1 获取当前用户结算中心的所有key
                        key = "payment_%s*" %request.user.id
                        key_list = CONN.keys(key)
                        
                        
                    total_price = 0
                    discount = 0
                    
                    coupon_id_list = []
                    
                    course_dict = {}
                    
                    3.2 根据key获取结算中心的课程
                        for key in key_list:
                            id = CONN.hget(key,'id').decode()
                            name = CONN.hget(key,'name').decode()
                            price = CONN.hget(key,'price').decode()
                            period = CONN.hget(key,'period').decode()
                            default_coupon_id = CONN.hget(key,'default_coupon_id').decode()
                            coupon_dict = json.loads(CONN.hget(key,'coupon_dict').decode())
                            
                            # 用于计算总原价
                            total_price += price
                            
                            if default_coupon_id == 0:
                                # 未使用
                                discount += 0
                            else:
                                # 使用优惠券
                                if coupon_dict['type'] == 0:    
                                    discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']
                                elif coupon_dict['type'] == 1:
                                    pass 
                                elif coupon_dict['type'] == 2:
                                    discount += price * (100-折扣)/ 100
                            
                                coupon_id_list.append(default_coupon_id)
                            
                     
                            course_dict[id] = {
                                id = CONN.hget(key,'id').decode()
                                name = CONN.hget(key,'name').decode()
                                price = CONN.hget(key,'price').decode()
                                period = CONN.hget(key,'period').decode()
                                default_coupon_id = CONN.hget(key,'default_coupon_id').decode(),
                                price:999,
                                discount:99,
                                
                            }
                            
                    3
                        
                """
    
    
                # 4.处理未绑定课程的优惠券
                """
                    4.1 去redis中获取 global_coupon_2
                        
                        default_coupon_id = CONN.hget('global_coupon_2','default_coupon_id')
                        coupon_dict = CONN.hget('global_coupon_2','coupon_dict')
                        
                    4.2 判断是否使用优惠券
                        if default_coupon_id == 0:
                            pass
                        else:
                             # 使用优惠券
                                if coupon_dict['type'] == 0:    
                                    discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']
                                elif coupon_dict['type'] == 1:
                                    pass 
                                elif coupon_dict['type'] == 2:
                                    discount += price * (100-折扣)/ 100
                            
                                coupon_id_list.append(default_coupon_id)
            
                """
    
    
                # 5. 判断是否:total_price-discount-balance/10 = alipay
                # total_price = 0
                # discount = 0
                # balance
                # alipay
                # raise Exception('价格对不上')
    
    
                # 6. 生成订单
                """
                with transcation.atomic():
                    6.1  obj = models.Order.objects.create(...)
                    
                    6.2  创建多个订单详细
                        for k,v in course_dict.items():
                            detail = OrderDetail.objects.create(order=obj)
                                     EnrolledCourse.objects.create(..,order_detail=detail)
                                     
                    6.3 更新优惠券
                        count = models.CouponRecord.objects.filter(id__in=coupon_id_list).update(status=2)
                        if count != len(coupon_id_list):
                             报错..
                
                    6.4 更新贝里余额
                        models.account.objects.filter(id=request.user.id).update(balance=F('balance')-balance)
                        
                    6.5 创建贝里转账记录
                        models.TransactionRecord.objects.create(,,balance)
                
                """
    
                # 7. 生成去支付宝支付的连接
    
    
            except Exception as e:
                pass
    View Code

    代码解释

    1

    接收用户发送的数据

    """
    {'balance':1000,'alipay':228 }
    """
    balance = request.data.get('balance')
    alipay = request.data.get('alipay')

    点击立即支付后,前端只需要向后端发送2个数据就可以了

    一个是花费的贝里,一个是要付款的总价!那课程信息从哪里获取呢?从结算中心获取!

    结算中心的数据,就是用户要买的所有东西。

    为什么要发这2个数据呢?首先用户使用贝里,可以抵扣价格。比如10贝里,可以抵扣1块钱。

    前端计算好金额后,发送给后端。后端再计算一遍金额。确保金额一致,跳转到支付宝!为什么不直接跳转到支付宝呢?

    因为前端发送的数据,用爬虫手段可以伪造!

    2

    检验贝里余额是否够用

    if request.user.balance < balance:
        raise Exception('贝里余额不足')

    为什么要检测余额呢?因为数据可以伪造嘛,我发送1000万的贝里到后端,实际账号的贝里只有10。

    不验证的话,岂不血亏!

    3

    获取结算中心的每个课程信息并应用优惠券

    3.1 获取当前用户结算中心的所有key

    key = "payment_%s*" %request.user.id
    key_list = CONN.keys(key)

    结算中心的key规则为:payment_用户id_课程id。使用模糊匹配payment_用户id*就可以得到当前登录用户的所有课程。

    结算中心的数据结构为:

    {
        payment_用户id_课程id:{
            id:课程id,
            name:'课程名',
            img:'课程图片',
            price:'原价',
            period:'有效期',
            period_display:'有效期中文显示',
            default_coupon_id:'默认优惠券id',
            # 当前课程所有绑定的优惠券
            coupon_dict:{
                # 这里的1,2,3是正序的序号而已。可以有几十张优惠券!
                '1':{'type':0,'text':'立减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':None},
                '2':{'type':0,'text':'满减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':'最低消费'},
                '3':{'type':0,'text':'折扣','money_equivalent_value':None,'off_percent':'百分比','minimum_consume':None},
            }
        },
        # 未绑定课程优惠券,也就是通用优惠券
        global_coupon_用户id:{
            default_coupon_id:'默认优惠券id',
            # 当前用户所有通用优惠券
            coupon_dict:{
                # 这里的1,2,3是正序的序号而已。可以有几十张优惠券!
                '1':{'type':0,'text':'立减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':None},
                '2':{'type':0,'text':'满减','money_equivalent_value':'等值货币','off_percent':None,'minimum_consume':'最低消费'},
                '3':{'type':0,'text':'折扣','money_equivalent_value':None,'off_percent':'百分比','minimum_consume':None},
            }
        }
    }

    3.2 根据key获取结算中心的课程

    下面获取的数据,分别为:课程id,课程名,课程图片,原价,有效期,有效期中文显示,默认优惠券id,当前课程所有绑定的优惠券

    for key in key_list:
        id = CONN.hget(key,'id').decode('utf-8')
        name = CONN.hget(key,'name').decode('utf-8')
        img = CONN.hget(key,'img').decode('utf-8')
        price = CONN.hget(key,'price').decode('utf-8')
        period = CONN.hget(key,'period').decode('utf-8')
        period_display = CONN.hget(key,'period_display').decode('utf-8')
        default_coupon_id = CONN.hget(key,'default_coupon_id').decode('utf-8')
        coupon_dict = json.loads(CONN.hget(key,'coupon_dict').decode('utf-8'))

    3.3 计算总原价

    total_price += price

    这里表示结算中心所有课程的总原价

    3.4 计算要抵扣的价格

    if default_coupon_id == 0:
        # 未使用
        discount += 0
    else:
        # 使用优惠券
        if coupon_dict['type'] == 0:    
            discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']
        elif coupon_dict['type'] == 1:
            pass 
        elif coupon_dict['type'] == 2:
            discount += price * (100-折扣)/ 100
    
        coupon_id_list.append(default_coupon_id)

     coupon_dict['type'] 为0,表示立减。它只和money_equivalent_value(等值货币)有关。等值货币,相当于人民币,可以直接扣

     coupon_dict['type'] 为1,表示满减券,它与money_equivalent_value和minimum_consume(最低消费)有关。

    coupon_dict['type'] 为2,表示折扣券,它只和off_percent有关。80表示80%,所以计算的时候,要除以100

    4

    处理未绑定课程的优惠券(通用优惠券)

    4.1 去redis中获取 global_coupon_用户id

    下面的代码,表示获取默认优惠券以及所有的

    default_coupon_id = CONN.hget('global_coupon_1','default_coupon_id')
    coupon_dict = CONN.hget('global_coupon_1','coupon_dict')

    4.2 判断是否使用优惠券

    if default_coupon_id == 0:
        pass
    else:
         # 使用优惠券
            if coupon_dict['type'] == 0:    
                discount += price if coupon_dict['money_equivalent_value'] > price else coupon_dict['money_equivalent_value']
            elif coupon_dict['type'] == 1:
                pass 
            elif coupon_dict['type'] == 2:
                discount += price * (100-折扣)/ 100
        
            coupon_id_list.append(default_coupon_id)
    View Code

    5

    判断前端发送的金额和后端计算的金额是否一致

    if total_price-discount-balance/10 != alipay:
        raise Exception('价格对不上')

    意思是总价格-要抵扣的价格-贝里/10。10贝里,表示1块钱。

    alipay 表示后台计算的价格

    6

    生成订单

    6.1 插入订单表,注意:使用事务。因为接下来要插入多张表

    with transcation.atomic():
        obj = models.Order.objects.create(...)

    6.2  创建多个订单详细

    for k,v in course_dict.items():
        detail = OrderDetail.objects.create(order=obj)
        EnrolledCourse.objects.create(..,order_detail=detail)

    EnrolledCourse 是 报名专题课表

    6.3 更新优惠券

    count = models.CouponRecord.objects.filter(id__in=coupon_id_list).update(status=2)
    if count != len(coupon_id_list):
         报错..

    上面这条数据,表示批量更新。至于count的返回值是什么,我不确定。

    在使用更新一条数据时,如果成功返回1,否则返回0

    6.4 更新贝里余额

    models.account.objects.filter(id=request.user.id).update(balance=F('balance')-balance)

    因为需要对某条字段的数值进行更新,需要用到F查询。

    6.5 创建贝里转账记录

    models.TransactionRecord.objects.create(,,balance)

    如果用户使用了贝里抵扣,这里需要创建一条记录才行

    7. 生成去支付宝支付的连接

    生成链接,主要让ajax跳转的。前端不能直接跳转,需要后端提供链接才行

    到这里基本上,就结束了。有兴趣的,可以继续写下面的需求

    8. 更新订单状态

    obj = models.Order.objects.filter(id=xx).update(payment_type_choices=1,payment_number=xxx,status=0)

    payment_type_choices 表示支付方式,1为支付宝。目前只支持支付宝!

    payment_number 表示支付第3方订单号。用户付款成功后,支付宝会发送一条POST请求,此时会携带支付宝的订单号。这个字段就是记录它的,用于以后的账单查询!

    status=0 表示交易成功

    9. 发送一条信息给boss

    有人买了课程了,boss当然是很开心的!

    相关代码,请访问github

    https://github.com/987334176/luffycity/archive/v1.6.zip 

    作业

    1. 结算中心
    2. 立即支付

    这2个功能,继续完善代码!

    路飞学城项目,到这里,就结束了!

    没有前端页面,真不好调试。

    使用django增加加了几个页面,功能只到购物车!

    首页

    课程

    课程详情

    购物车

    完整代码,请参数github

    https://github.com/987334176/luffycity/archive/v1.7.zip

  • 相关阅读:
    HDU 4379 水题,大水,但我WA了很多次,做了很久
    HDU 1712分组背包 考试复习安排
    所谓的二维背包Triangular Pastures POJ 1948
    ZOJ 1203 Swordfish Kruskal算法求最小生成树
    POJ 2576 Tug of War二维背包恰好装满.
    O(n*m)复杂度的多重背包coinsPOJ 1742
    拓扑排序POJ 1094
    页面右键下拉表
    gb2312 unicode转换工具
    INPUT读出URL里的变量名称
  • 原文地址:https://www.cnblogs.com/xiao987334176/p/9487528.html
Copyright © 2020-2023  润新知