GO语言开发天天生鲜项目第五天 购物车模块和订单模块

Posted 办公模板库 素材蛙

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了GO语言开发天天生鲜项目第五天 购物车模块和订单模块相关的知识,希望对你有一定的参考价值。

商品模块

商品详情页Js实现

在开始购物车模块之前,我们先把商品模块最后一个知识点实现。打开我们的商品详情页,这个页面的改变商品数量,获取总价的功能我们还没有实现。商品详情页的页面显示如下:

计算商品总价

思考什么时候计算商品总价?

当商品数量改变的时候需要重新计算商品总价。因为我们详情页这里可以添加商品数量,减少商品数量,修改商品数量以及刚加载页面的时候都需要计算商品总价,所以我们把计算商品总价这个业务封装成一个函数。

  • 定义计算商品总价函数

    function UpdateGoodsPrice() 
    
  • 获取商品数量和单价

    由视图代码可以找到,商品单价标签是class=show_pirze的子标签,所以获取单价的代码为:

    price = $('.show_pirze').children('em').text()
    

    商品的数量标签是class=num_show的标签,则获取数量的代码为:

    count = $('.num_show').val()
    
  • 计算总价

    在计算总价之前需要注意,我们这时候获取的price和count都是字符串类型,需要做类型转换之后才能做运算。代码如下:

    //计算商品总价
    price = parseFloat(price)
    count = parseInt(count)
    amount = price * count
    
  • 设置总价

    显示总价的标签为class=total的子标签,同时我们设置总价的时候,价格有两位小数点,设置总价代码如下:

    $('.total').children('em').text(amount.toFixed(2)+'元')
    

全部函数代码如下:

//计算商品总价
function UpdateGoodsPrice() 
    //获取单价和数量
    price = $('.show_pirze').children('em').text()
    count = $('.num_show').val()
	//计算商品总价
	price = parseFloat(price)
	count = parseInt(count)
	amount = price * count
	//设置总价
    $('.total').children('em').text(amount.toFixed(2)+'元')

注意:当我们加载页面的时候就要计算总价,所以要在外面提前调用一下这个函数

添加商品数量

当点击+超链接的时候显示栏的数量就添加1,这里我们通过js控制显示数量的增加

  • 获取到按钮的点击事件

    通过代码发现+这个超链接的class为add,所以按钮的点击事件为:

    $('.add').click(function () )
    
  • 获取原来显示框的数量

    count = $('.num_show').val()
    
  • 原来的数量加一

    count = parseInt(count) + 1
    

    直接获取的count类型为string类型,需要先转为Int类型,然后再进行加法运算

  • 在显示框中显示

    $('.num_show').val(count)
    
  • 更新总价

    //更新总价
    UpdateGoodsPrice()
    

全部代码:

$('.add').click(function () 
    //获取原来的数量,加一
	count = $('.num_show').val()
	count = parseInt(count) + 1
	//重新设置数目
	$('.num_show').val(count)
    //更新总价
	UpdateGoodsPrice()
)

减少商品数量

逻辑和增加商品数量一样,但是需要做一个简单的判断,代码如下:

$('.minus').click(function () 
    //获取原来的数量,加一
    count = $('.num_show').val()
    count = parseInt(count) - 1
	//对数据大小进行判断
	if (count < 1)
        count = 1
	
    //重新设置数目
    $('.num_show').val(count)
    //更新总价
	UpdateGoodsPrice()
)

手动设置商品数量

除了点击按钮外,我们还能够直接在input框中输入商品数量,然后获取总价。那我们什么时候获取这个手动的商品数量呢?一般是当这个input标签失去焦点的时候,我们开始获取手动设置的商品数量。

  • 失去焦点的时候获取商品数量,相应函数如下:

    $('.num_show').blur(function () 
    
  • 获取输入的商品数量

    count = $(this).val()
    

    当响应函数内部获取某个标签的时候,如果这个标签和出发这个事件的标签一致,可以用this代替

  • 对输入的数据进行校验

    如果用户输入的数据是字母,一堆空格,或者小于1,这时候我们认为用户输入数据非法,需要手动设置一个正确的数值。代码如下:

    if(isNaN(count) || count.trim().length == 0||parseInt(count)<1)
    	count = 1
    
    
  • 然后再次设置数量

    $(this).val(count)
    
  • 更新商品总价

    UpdateGoodsPrice()
    

全部代码如下:

$('.num_show').blur(function () 
	count = $(this).val()
	if(isNaN(count) || count.trim().length == 0||parseInt(count)<1)
	    count = 1
	
	$(this).val(count)
	UpdateGoodsPrice()
)

购物车模块

1.添加购物车数据

我们这时候再回到商品详情页,这个页面有个添加购物车按钮。那我们就在这里实现这个功能。这时候需要思考一个问题,我们向数据库中添加购物车数据的时候,页面要全部刷新吗?

一般情况下,我们向数据库中添加购物车数据的时候,页面只是进行局部刷新。局部刷新我们一般用ajax来实现这个功能,那这里我们就用ajax发送请求。

请求

添加购物车,需要传递数据,我们一般是用post请求,函数名是$.post(),有三个参数,第一个参数是请求路径,第二个参数是传递的数据(json格式的数据),第三个参数是成功后所执行的函数

所以在发送请求之前,我们需要先确定请求路径,添加购物车数据需要登陆的状态下才能进行,所以我们设置请求路径为/user/addCart。

接着我们要去构造传递的数据,添加购物车,需要把商品id对应的数量传递给后台,这里我们设计数据格式为“skuid”:id,“count”:count。

最后是我们的函数。代码如下:

  • 封装要传递的数据

    我们要传递的数据为商品的id,所以我们需要获取这个id,但是这时候你发现,我们页面里面没有显示商品id的地方。那这里需要我们手动在页面里面添加这个内容,有两种解决方法:

    第一种:隐藏域传值,这个方法我们前面用过,不做详细介绍。

    第二种:给某一个标签添加一个自定义属性,获取这个属性的值,这里我们给加入购物车按钮添加一个商品ID属性,代码如下:

    
    

    获取自定义属性的值,使用attr()方法。具体代码如下:

    skuid = $('#add_cart').attr("skuid")
    

    获取商品数量,直接获取相应标签值即可,代码如下:

    count =  $('.num_show').val()
    

    封装成一个json格式的数据包,代码如下:

    params = 'skuid':skuid,'goodsCount':count
    
  • 发送请求

    $.post('/user/addCart',params,function (data) 

路由

ajax发送了请求之后,我们要在router.go中添加相对应的控制器和方法。

 beego.Router("/user/addCart",&controllers.CartController,"post:HandleAddCart")

控制器

在路由指定了控制器和方法之后,我们就创建控制器并且实现HandleAddCart方法。

  • 获取数据

    skuid,err1 := this.GetInt("skuid")
    count,err2 := this.GetInt("goodsCount")
    
  • 校验数据

    校验数据传输是否正确

    //返回数据
    resp := make(map[string]interface)
    defer this.ServeJSON()
    
    //数据校验
    if err1 != nil || err2 != nil
    	resp["res"]=1
    	resp["errmsg"] = "获取数据信息错误"
    	this.Data["json"] = resp
    	return
    
    

    注意,ajax传递过来的数据,我们回复的时候不再指定视图,而是回复给视图json格式的数据。那这里我们怎么给视图中传递json数据呢?

    首先定义一个map[string]interface类型,用来存储返回的数据,然后指定传递的数据代码为:

    this.Data["json"] = resp
    

    接着调用传递数据函数:

    this.ServeJSON()
    

    不管能不能执行成功我们都要给ajax请求返回数据,所以这里我们可以直接defer调用函数的代码。

    校验传过来的商品id是否有对应的商品数据

    o := orm.NewOrm()
    var goods models.GoodsSKU
    goods.Id = skuid
    err := o.Read(&goods)
    if err != nil
    	resp["res"]=2
    	resp["errmsg"] = "商品不存在"
    
    

    校验添加商品的数量是否超出我们的库存

    
    

    校验登陆状态

    userName := this.GetSession("userName")
    if userName == nil
    	resp["res"]=4
    	resp["errmsg"] = "用户未登录,请提前登录"
    	this.Data["json"] = resp
    	return
    
    

    思考:我们这个请求都是在登陆状态下才能发的,那我这个校验还有意义没有?

  • 处理数据

    添加购物车数据其实就是向数据库中添加数据。那这时候我们思考以下几个问题:

    第一:添加哪些数据?

    第二:用哪种数据库?用哪种类型?

    第一个问题的答案跟明确,我们要添加当前用户对应的商品,和商品数量。

    根据第一个问题的答案我们分析出来,我们数据库中要存储用户信息,商品信息,商品数量,并且这三者还是一一对应的。那我们分析之后可以得出,用redis中的hash存储这个数据最合适。

    那我们就给redis中设置一个hash值。

    但是在添加这个记录之前,如果redis中该用户已经添加过该商品数据,那么我们做的就是累加操作。具体代码如下:

    conn,_:=redis.Dial("tcp",":6379")
    preCount,_:=redis.Int(conn.Do("hget","cart_"+strconv.Itoa(user.Id),skuid))
    conn.Do("hset","cart_"+strconv.Itoa(user.Id),skuid,count+preCount)
    
  • 查询购物车中商品数量

    //获取购物车商品个数
    cartcount,_ :=redis.Int(conn.Do("hlen","cart_"+strconv.Itoa(user.Id)))
    
    
  • 返回数据

    resp["res"] = 5
    resp["cartcount"]=cartcoun
    this.Data["json"] = resp
    

视图

这时候ajax能够拿到数据,我们就需要在回调函数里面做一个处理。具体处理如下(是一个执行动画操作,我们不需要详细了解,课堂上带你们看一下,知道即可):

$.post('goods/cartAdd',params,function (data) 
	if(data.res == 5)
	    //添加成功
        $(".add_jump").css('left':$add_y+80,'top':$add_x+10,'display':'block')
        $(".add_jump").stop().animate(
                    'left': $to_y+7,
                    'top': $to_x+7,
                "fast", function() 
                    $(".add_jump").fadeOut('fast',function()
                        $('#show_count').html(data.cartcount);
                    );
                );
	else
	    //添加失败
		alert(data.errmsg)
	
)

到这里添加购物车内容基本实现,接着需要把项目中很多地方的添加购物车按钮都实现相应的超链接。

2.获取购物车条目数

添加完购物车内容,我们就需要去获取相关数据,我们发现在很多页面都需要展示购物车条目数,如图:

那么我们可以在后台封装一个获取购物车数据条目数的函数,加载各个页面的时候调用,代码如下:

func GetCartCount(this*beego.Controller)int
	userName := this.GetSession("userName")
	if userName == nil
		return 0
	
	o := orm.NewOrm()
	var user models.User
	user.Name = userName.(string)
	o.Read(&user,"Name")

	conn,_ := redis.Dial("tcp","192.168.110.81:6379")
	rep,err :=conn.Do("hlen","cart_"+strconv.Itoa(user.Id))
	cartCount ,_ :=redis.Int(rep,err)
	return cartCount

3.购物车页面展示

请求

我们每个页面头部有一个导航栏,叫我的购物车,这个超链接就是发起购物车页面请求的。查看购物车数据需要在登陆的状态下才能够查看,所以这里我们设计访问购物车页面的请求为:/user/cart

路由

有了请求,需要到router.go中指定相应的控制器和方法。代码如下:

beego.Router("/user/cart",&controllers.CartController,"get:ShowCart")

控制器

接着我们在控制器中实现ShowCart函数。

  • 从redis中获取数据

    因为我们前面设计的redis中存储购物车数据的key值是cart_userId,所以我们要先获取用户Id,代码如下:

    userName := this.GetSession("userName")
    o := orm.NewOrm()
    var user models.User
    user.Name = userName.(string)
    o.Read(&user,"Name")
    

    有了key值,我们就可以获取相应数据。这里注意我们要获取购物车存储数据的类型为hash,获取所有数据的命令为hgetall。这个命令返回的结果是一个map[string]int切片。所以这里我们获取所有购物车数据的代码如下:

    conn,_:=redis.Dial("tcp","192.168.110.81:6379")
    defer conn.Close()
    //以map[string]int的形式获取购物车数据
    reply,_:=redis.IntMap(conn.Do("hgetall","cart_"+strconv.Itoa(user.Id)))
    
  • 获取相应的商品数据

    这时候我们从redis数据库中获取到的是购物车中所有商品的ID和数量,视图中我们要获取的是确定的商品信息和数量 ,所以需要我们从数据库中获取到商品信息并和数量一起存储。这里要注意,我们这里又需要一个容器,存储商品信息和数量两个不同的类型,参考我们首页讲过的内容,这里我们还用[]map[string]interface,我们的切片的长度就是从redis数据库中获取了几条数据,获取所有商品的代码如下:

    
    
  • 计算总的价格和总数量

    总价和总数量应该在循环获取商品的时候获取,这时候可以给总价个总数量做一个叠加。代码如下:

    //循环遍历,获取购物车商品数据
    	totalCount := 0
    	totalPrice := 0
    	i := 0
    	for index,count := range reply
    		temp := make(map[string]interface)
    		var goods models.GoodsSKU
    		id,_ := strconv.Atoi(index)
    		goods.Id = id
    		o.Read(&goods)
    		temp["goods"] = goods
    		temp["count"] = count
    		cartGoods[i] = temp
    		totalCount += count
    		totalPrice += goods.Price * count
    		i += 1
    	
    
  • 把获取到的总结,总数量,所有商品传递给视图

    this.Data["totalCount"] = totalCount
    this.Data["totalPrice"] = totalPrice
    this.Data["goods"] = cartGoods
    

视图

视图中获取到数据之后,需要在视图中循环显示,代码如下:

range .goods
    <ul class="cart_list_td clearfix">
    	<li class="col01"><input type="checkbox" name="skuids" value=".goods.Id" checked></li>
    	<li class="col02"><img src="http://192.168.110.81:8888/.goods.Image"></li>
    	<li class="col03">.goods.Name<br><em>.goods.Price元/.goods.Unite</em></li>
    	<li class="col04">.goods.Unite</li>
    	<li class="col05">.goods.Price元</li>
    	<li class="col06">
    		<div class="num_add">
    			<a href="javascript:;" class="add fl">+</a>
    			<input type="text" class="num_show fl" skuid = .goods.Id value=".count">
    			<a href="javascript:;" class="minus fl">-</a>
    		</div>
    	</li>
    	<li class="col07">.amount元</li>
    	<li class="col08"><a href="javascript:;" class="deleteCart">删除</a></li>
    </u

新星计划Django基于PythonWeb的Django框架设计实现天天生鲜系统-9购物车提交订单订单提交成功页面功能实现

购物车页面功能实现

购物车页面主要两个功能:

  1. 显示购物车商品详细数据.

  2. 增加商品删除功能.

我们在 cart 应用的 views.py 模块中增加 show_cart 视图函数, 来显示购物车商品数据, 代码如下:

def show_cart(request):
    """展示购物车商品"""
​
    # 读取购物车商品列表
    cart_goods_list = []
    # 商品总数
    cart_goods_count = 0
    # 商品总价
    cart_goods_money = 0
    for goods_id, goods_num in request.COOKIES.items():
        if goods_id == 'csrftoken':
            continue
​
        cart_goods = GoodsInfo.objects.get(id=goods_id)
        cart_goods.goods_num = goods_num
        cart_goods.total_money = int(goods_num) * cart_goods.goods_price
        cart_goods_list.append(cart_goods)
        # 累加购物车商品总数
        cart_goods_count = cart_goods_count + int(goods_num)
        # 累计商品总价
        cart_goods_money += int(goods_num) * cart_goods.goods_price
​
    return render(request, 'cart.html', {'cart_goods_list': cart_goods_list,
                                         'cart_goods_count': cart_goods_count,
                                         'cart_goods_money': cart_goods_money})

cart.html 模板代码数据如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>天天生鲜-购物车</title>
    <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
    <link rel="stylesheet" type="text/css" href="/static/css/main.css">
</head>
<body>
    <div class="header_con">
        <div class="header">
            <div class="welcome fl">欢迎来到天天生鲜!</div>
        </div>      
    </div>
​
    <div class="search_bar clearfix">
        <a href="index.html" class="logo fl"><img src="/static/images/logo.png"></a>
        <div class="sub_page_name fl">|&nbsp;&nbsp;&nbsp;&nbsp;购物车</div>    
    </div>
​
    <div class="total_count">全部商品<em>{{ cart_goods_count }}</em>件</div>
    <ul class="cart_list_th clearfix">
        <li class="col01">商品名称</li>
        <li class="col02">商品单位</li>
        <li class="col03">商品价格</li>
        <li class="col04">数量</li>
        <li class="col05">小计</li>
        <li class="col06">操作</li>
    </ul>
​
    {% for cart_goods in cart_goods_list %}
    <ul class="cart_list_td clearfix">
        <li class="col01"></li>
        <li class="col02"><img src="/static/{{ cart_goods.goods_img }}"></li>
        <li class="col03">奇异果<br><em>{{ cart_goods.goods_price }}元/{{ cart_goods.goods_unit }}</em></li>
        <li class="col04">{{ cart_goods.goods_unit }}</li>
        <li class="col05">{{ cart_goods.goods_price }}元</li>
        <li class="col06">{{ cart_goods.goods_num }}</li>
        <li class="col07">{{ cart_goods.goods_price }}元</li>
        <li class="col08"><a href="/cart/remove_cart/?id={{ cart_goods.id }}">删除</a></li>
    </ul>
    {% endfor %}
​
    <ul class="settlements">
        <li class="col01">.</li>
        <li class="col02">.</li>
        <li class="col03">合计(不含运费):<span>¥</span><em>{{ cart_goods_money }}</em><br>共计<b>{{ cart_goods_count }}</b>件商品</li>
        <li class="col04"><a href="/cart/place_order/">去结算</a></li>
    </ul>
​
    <div class="footer">
        <div class="foot_link">
            <a href="#">关于我们</a>
            <span>|</span>
            <a href="#">联系我们</a>
            <span>|</span>
            <a href="#">招聘人才</a>
            <span>|</span>
            <a href="#">友情链接</a>        
        </div>
        <p>CopyRight © 2016 北京天天生鲜信息技术有限公司 All Rights Reserved</p>
        <p>电话:010-****888    京ICP备*******8号</p>
    </div>
    
</body>
</html>

如下模板代码用于显示购物车商品数据:

{% for cart_goods in cart_goods_list %}
<ul class="cart_list_td clearfix">
    <li class="col01"></li>
    <li class="col02"><img src="/static/{{ cart_goods.goods_img }}"></li>
    <li class="col03">奇异果<br><em>{{ cart_goods.goods_price }}元/{{ cart_goods.goods_unit }}</em></li>
    <li class="col04">{{ cart_goods.goods_unit }}</li>
    <li class="col05">{{ cart_goods.goods_price }}元</li>
    <li class="col06">{{ cart_goods.goods_num }}</li>
    <li class="col07">{{ cart_goods.goods_price }}元</li>
    <li class="col08"><a href="/cart/remove_cart/?id={{ cart_goods.id }}">删除</a></li>
</ul>
{% endfor %}

如下代码显示购物车的总商品数量、商品总价:

<li class="col03">合计(不含运费):<span>¥</span><em>{{ cart_goods_money }}</em><br>共计<b>{{ cart_goods_count }}</b>件商品</li>

我们的购物车页面提供了删除购物车商品的功能, 该功能的链接代码如下:

<li class="col08"><a href="/cart/remove_cart/?id={{ cart_goods.id }}">删除</a></li>

当用户要删除某个购物车商品时, 该请求由 cart 应用下的 remove_cart 视图来处理, 该视图函数实现如下:

def remove_cart(request):
    """删除购物车商品"""
​
    # 获得要删除的商品ID
    goods_id = request.GET.get('id', '')
    if goods_id:
        # 获得上一页面地址
        prev_url = request.META['HTTP_REFERER']
        # 写入到 cookie 中
        response = redirect(prev_url)
        # 判断商品是否存在
        goods_count = request.COOKIES.get(goods_id, '')
        if goods_count:
            response.delete_cookie(goods_id)
​
    return response

首先要获得删除商品的 ID, 代码如下:

goods_id = request.GET.get('id', '')

如果该商品在购物车中存在, 则删除它. 删除完成之后跳转到上一页面, 也就是购物车页面, 代码如下:

if goods_id:
    # 获得上一页面地址
    prev_url = request.META['HTTP_REFERER']
    # 写入到 cookie 中
    response = redirect(prev_url)
    # 判断商品是否存在
    goods_count = request.COOKIES.get(goods_id, '')
    if goods_count:
        response.delete_cookie(goods_id)

提交订单页面功能实现

当购物车商品数据确认无误之后, 点击结算按钮跳转到订单提交页面, 在该页面用户就需要填写收货地址、联系电话、联系人等信息.

我们在 cart 应用下的 views.py 模块中新增如下视图函数:

def place_order(request):
    """提交订单页面"""
​
    # 读取购物车商品列表
    cart_goods_list = []
    # 商品总数
    cart_goods_count = 0
    # 商品总价
    cart_goods_money = 0
    for goods_id, goods_num in request.COOKIES.items():
        if goods_id == 'csrftoken':
            continue
​
        cart_goods = GoodsInfo.objects.get(id=goods_id)
        cart_goods.goods_num = goods_num
        cart_goods.total_money = int(goods_num) * cart_goods.goods_price
        cart_goods_list.append(cart_goods)
        # 累加购物车商品总数
        cart_goods_count = cart_goods_count + int(goods_num)
        # 累计商品总价
        cart_goods_money += int(goods_num) * cart_goods.goods_price
​
    return render(request, 'place_order.html', {'cart_goods_list': cart_goods_list,
                                                'cart_goods_count': cart_goods_count,
                                                'cart_goods_money': cart_goods_money})

并在 ttsx/urls.py 模块中配置该视图对应的请求网址, 新增配置如下:

from django.conf.urls import include, url
from django.contrib import admin
from goods.views import index  # 导入视图函数
from goods.views import detail
from goods.views import goods
from cart.views import add_cart
from cart.views import show_cart
from cart.views import place_order
​
urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^index/$', index),
    url(r'^detail/$', detail),
    url(r'^cart/add_cart/$', add_cart),
    url(r'^goods/$', goods),
    url(r'^cart/show_cart/$', show_cart),
    url(r'^cart/place_order/$', place_order),
]

cart.html 模板代码如下:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
    <meta http-equiv="Content-Type" content="text/html;charset=UTF-8">
    <title>天天生鲜-提交订单</title>
    <link rel="stylesheet" type="text/css" href="/static/css/reset.css">
    <link rel="stylesheet" type="text/css" href="/static/css/main.css">
</head>
<body>
    <div class="header_con">
        <div class="header">
            <div class="welcome fl">欢迎来到天天生鲜!</div>
        </div>      
    </div>
​
    <div class="search_bar clearfix">
        <a href="/" class="logo fl"><img src="/static/images/logo.png"></a>
        <div class="sub_page_name fl">|&nbsp;&nbsp;&nbsp;&nbsp;提交订单</div>   
    </div>
    
​
    <h3 class="common_title">商品列表</h3>
    <div class="common_list_con clearfix">
        <ul class="goods_list_th clearfix">
            <li class="col01">商品名称</li>
            <li class="col02">商品单位</li>
            <li class="col03">商品价格</li>
            <li class="col04">数量</li>
            <li class="col05">小计</li>       
        </ul>
​
        {% for cart_goods in cart_goods_list %}
        <ul class="goods_list_td clearfix">
            <li class="col01">1</li>            
            <li class="col02"><img src="/static/{{ cart_goods.goods_img }}"></li>
            <li class="col03">{{ cart_goods.goods_name }}</li>
            <li class="col04">{{ cart_goods.goods_unit }}</li>
            <li class="col05">{{ cart_goods.goods_price }}元</li>
            <li class="col06">{{ cart_goods.goods_num }}</li>
            <li class="col07">{{ cart_goods.total_money }}元</li>
        </ul>
        {% endfor %}
​
    </div>
​
    <h3 class="common_title">收货地址</h3>
    <form action="/cart/submit_order/" method="post">
    {% csrf_token %}
    <div class="common_list_con clearfix">
        <dl>
            <dd>
                <table>
                    <tr>
                        <td>收货地址:</td><td><input style="width: 350px; height: 23px;" type="text" name="addr"></td>
                    </tr>
                    <tr>
                        <td>收货人:</td><td><input style="width: 350px; height: 23px;" type="text" name="recv"></td>
                    </tr>
                    <tr>
                        <td>联系电话:</td><td><input style="width: 350px; height: 23px;" type="text" name="tele"></td>
                    </tr>
                    <tr>
                        <td>备注:</td><td><textarea style="width: 350px; height: 100px; font-size: 12px;" name="extra"></textarea></td>
                    </tr>
                </table>
            </dd>
        </dl>
    </div>
​
    <h3 class="common_title">支付方式</h3>  
    <div class="common_list_con clearfix">
        <div class="pay_style_con clearfix">
            <input type="radio" name="pay_style" checked>
            <label class="cash">货到付款</label>
        </div>
    </div>
​
    <h3 class="common_title">总金额结算</h3>
    <div class="common_list_con clearfix">
        <div class="settle_con">
            <div class="total_goods_count">共<em>{{ cart_goods_count }}</em>件商品,总金额<b>{{ cart_goods_money }}元</b></div>
            <div class="transit">运费:<b>10元</b></div>
            <div class="total_pay">实付款:<b>{{ cart_goods_money|add:10 }}元</b></div>
        </div>
    </div>
​
​
    <div class="order_submit clearfix">
        <input type="submit" value="提交订单"/>
    </div>  
    </form>
​
    <div class="footer">
        <div class="foot_link">
            <a href="#">关于我们</a>
            <span>|</span>
            <a href="#">联系我们</a>
            <span>|</span>
            <a href="#">招聘人才</a>
            <span>|</span>
            <a href="#">友情链接</a>        
        </div>
        <p>CopyRight © 2016 北京天天生鲜信息技术有限公司 All Rights Reserved</p>
        <p>电话:010-****888    京ICP备*******8号</p>
    </div>
​
    <div class="popup_con">
        <div class="popup">
            <p>订单提交成功!</p>
        </div>
        
        <div class="mask"></div>
    </div>
</body>
</html>

我们在模板中新增了一个 form 表单用于提交订单数据, 代码如下:

 <form action="/cart/submit_order/" method="post">
    {% csrf_token %}
    <div class="common_list_con clearfix">
        <dl>
            <dd>
                <table>
                    <tr>
                        <td>收货地址:</td><td><input style="width: 350px; height: 23px;" type="text" name="addr"></td>
                    </tr>
                    <tr>
                        <td>收货人:</td><td><input style="width: 350px; height: 23px;" type="text" name="recv"></td>
                    </tr>
                    <tr>
                        <td>联系电话:</td><td><input style="width: 350px; height: 23px;" type="text" name="tele"></td>
                    </tr>
                    <tr>
                        <td>备注:</td><td><textarea style="width: 350px; height: 100px; font-size: 12px;" name="extra"></textarea></td>
                    </tr>
                </table>
            </dd>
        </dl>
    </div>
​
    <h3 class="common_title">支付方式</h3>  
    <div class="common_list_con clearfix">
        <div class="pay_style_con clearfix">
            <input type="radio" name="pay_style" checked>
            <label class="cash">货到付款</label>
        </div>
    </div>
​
    <h3 class="common_title">总金额结算</h3>
    <div class="common_list_con clearfix">
        <div class="settle_con">
            <div class="total_goods_count">共<em>{{ cart_goods_count }}</em>件商品,总金额<b>{{ cart_goods_money }}元</b></div>
            <div class="transit">运费:<b>10元</b></div>
            <div class="total_pay">实付款:<b>{{ cart_goods_money|add:10 }}元</b></div>
        </div>
    </div>
​
​
    <div class="order_submit clearfix">
        <input type="submit" value="提交订单"/>
    </div>  
    </form>
​

该 form 表单将订单数据提交到 /cart/submit_order/ 页面进行处理, 代码如下:

 <form action="/cart/submit_order/" method="post">
    {% csrf_token %}

其中 {% csrf_token %} 主要用于安全设置, 这是django提供的防护错误, 用于防护跨站请求伪造. 在如果提交的表单是以 post 方式提交的话, 那么需要我们在 form 表单内部加上该代码.

代码 {{ cart_goods_money|add:10 }} 的含义为 cart_goods_money 的值 加上10. add 是django模板语法中提供的过滤器函数, 使用语法就是:

{{ 变量|过滤器函数:参数 }}

用户填写完收货信息之后, 点击提交订单按钮, 将表单提交到了 /cart/submit_order/ 页面, 我们在 cart 应用下的 views.py 模块中新增 submit_order 视图函数用于处理订单提交. 该视图函数实现如下:

def submit_order(request):
    """保存订单"""
​
    # 获得订单信息
    addr = request.POST.get('addr', '')
    recv = request.POST.get('recv', '')
    tele = request.POST.get('tele', '')
    extra = request.POST.get('extra', '')
​
    # 保存订单信息
    order_info = OrderInfo()
    order_info.order_addr = addr
    order_info.order_tele = tele
    order_info.order_recv = recv
    order_info.order_extra = extra
    # 生成订单编号
    order_info.order_id = str(int(time.time() * 1000)) + str(int(time.clock() * 1000000))
    order_info.save()
​
    # 跳转页面
    response = redirect('/cart/submit_success/?id=%s' % order_info.order_id)
​
    # 保存订单商品信息
    for goods_id, goods_num in request.COOKIES.items():
        if goods_id == 'csrftoken':
            continue
        # 查询商品信息
        cart_goods = GoodsInfo.objects.get(id=goods_id)
        # 创建订单商品信息
        order_goods = OrderGoods()
        order_goods.goods_info = cart_goods
        order_goods.goods_order = order_info
        order_goods.goods_num = goods_num
        order_goods.save()
        # 删除购物车信息
        response.delete_cookie(goods_id)
​
    return response

配置该视图与网址的对应关系, 编辑 ttsx/urls.py 模块如下:

from django.conf.urls import include, url
from django.contrib import admin
from goods.views import index  # 导入视图函数
from goods.views import detail
from goods.views import goods
from cart.views import add_cart
from cart.views import show_cart
from cart.views import place_order
from cart.views import submit_order
​
urlpatterns = [
    url(r'^admin/', include(admin.site.urls)),
    url(r'^index/$', index),
    url(r'^detail/$', detail),
    url(r'^cart/add_cart/$', add_cart),
    url(r'^goods/$', goods),
    url(r'^cart/show_cart/$', show_cart),
    url(r'^cart/place_order/$', place_order),
    url(r'^cart/submit_order/$', submit_order),
]

首先我们获得表单提交的数据, 这里需要大家注意, 如果表单以 post 方提交的话, 那么表单中提交的数据会被存储在 request 对象的 POST 字典中.

# 获得订单信息
addr = request.POST.get('addr', '')
recv = request.POST.get('recv', '')
tele = request.POST.get('tele', '')
extra = request.POST.get('extra', '')

我们的订单信息保存分为两部分, 第一部分是订单基本信息, 存储在 OrderInfo 模型所对应的数据库表中, 代码如下:

# 保存订单信息
order_info = OrderInfo()
order_info.order_addr = addr
order_info.order_tele = tele
order_info.order_recv = recv
order_info.order_extra = extra
# 生成订单编号
order_info.order_id = str(int(time.time() * 1000)) + str(int(time.clock() * 1000000))
order_info.save()

然后将订单中的商品信息存储在 OrderGoods 模型所对应的表中. 首先我们创建了一个重定向响应对象, 指定订单提交成功之后要跳转的页面:

# 跳转页面
response = redirect('/cart/submit_success/?id=%s' % order_info.order_id)

然后保存订单商品信息到数据库中, 并删除购物车中商品数据, 代码如下:

# 保存订单商品信息
for goods_id, goods_num in request.COOKIES.items():
    if goods_id == 'csrftoken':
        continue
    # 查询商品信息
    cart_goods = GoodsInfo.objects.get(id=goods_id)
    # 创建订单商品信息
    order_goods = OrderGoods()
    order_goods.goods_info = cart_goods
    order_goods.goods_order = order_info
    order_goods.goods_num = goods_num
    order_goods.save()
    # 删除购物车信息
    response.delete_cookie(goods_id)

当订单提交成功之后, 删除购物车中的商品信息, 跳转到 submit_success 页面, 并传递过去订单编号.

以上是关于GO语言开发天天生鲜项目第五天 购物车模块和订单模块的主要内容,如果未能解决你的问题,请参考以下文章

新星计划Django基于PythonWeb的Django框架设计实现天天生鲜系统-10订单提交成功页面功能实现

天天生鲜 - App设计

Django基于PythonWeb的Django框架设计实现天天生鲜系统-1

天天生鲜(Python)Django项目学习资料(视频源码)

天天生鲜(Python)Django项目学习资料(视频源码)

基于springboot电商生鲜购物商城平台设计与实现(含源码+数据库文件)