使用Python的Django框架结合jQuery实现AJAX购物车页面


Posted in Python onApril 11, 2016

Django中集成jquery
首先,静态的资源通常放入static文件夹中:

static/
  css/
    djquery.css
    samples/
      hello.css
  js/
    jquery-1.7.1.min.js
    samples/
      hello.js

其中css和js都按照应用名称(这里是samples)划分文件夹,如果文件较多,还可以再划分子文件夹。

Django通常使用模板来展现html,而且我们通常使用继承的模板,所以需要将共用的元素,比如全局的css,对jquery.js的引入等,写到base模板中,而将具体页面的元素放到具体的模板中。这就牵涉到如何嵌套的问题。看下面的例子:
base.html

<html>
 <head>
  <meta charset="utf-8">
  <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
  <title>{% block title %} 标题 {% endblock %}</title>
  <link href="css/djquery.css" rel="stylesheet">
{% block styles %}<!--custom styles-->{% endblock %}
 </head>
 <body>
  <div id="container">
{% block content %}内容{% endblock %}
  </div>
</body>
<script language="JavaScript" type="text/javascript" src="/static/js/jquery-1.7.1.min.js"></script>
{% block scripts %}
<!--custom scripts-->
{% endblock %}
</html>

samples/hello.html

{% extends "base.html" %}

{% block title %}
hello, djquery! 
{% endblock %}

{% block styles %}
{% endblock %}

{% block content %}
<div><input type="button" id="myField" value="Click me!"/></div>
{% endblock %}

{% block scripts %}
<script language="JavaScript" type="text/javascript" src="/static/js/djquery/hello.js"></script>
{% endblock %}

Hello, Djquery!
有了上述的“框架”,我们就可以很容易的验证一下我们的想法,比如这个“Hello Djquery”。只需要在urls.py中配置一下:

(r'hello/$', 'django.views.generic.simple.direct_to_template', {'template':'samples/hello.html'}),

其中direct_to_template是django提供的一个通用视图。

AJAX实现示例
我们来看一个购物车的例子。假设现在我们有一个使用json格式的RESTful API,可以实现这样的功能了:为了避免在产品列表和购物车之间来回切换,需要在产品列表界面显示购物车,并且通过ajax的方式不刷新界面就更新购物车的显示内容,利用我们上面在Django中集成的jQuery。
1.嵌入购物车界面
为了实现如下图所示的嵌入购物车的产品目录界面,我们需要做两件事情:

使用Python的Django框架结合jQuery实现AJAX购物车页面

(1)修改模板:

depot/templates/depotapp/store.html:

{% extends "base.html" %} 
   
  {% block title %} 产品目录 {% endblock %} 
  {% block pagename %} 产品目录 {% endblock %} 
   
  {% block content %}  
  <div class="row"> 
    <div class="span10"> 
  {% for item in products %} 
  <div class="row" style="padding-top:10"> 
    <div class="span3 media-grid"> 
      <a href="#"> 
      <img class="thumbnail" src="{{item.image_url}}" alt=""> 
      </a> 
    </div> 
    <div class="span6"> 
      <h3>{{item.title}}</h3> 
      <br/> 
      {{item.description}} 
      <br/> 
      <br/> 
      <br/> 
      <div class="row"> 
        <div class="span2"><h3>¥{{item.price|floatformat:"2"}}</h3></div> 
        <div class="span"><a class="btn primary" href="{% url depotapp.views.add_to_cart item.id %}">加入购物车</a></div> 
      </div> 
    </div> 
   
  </div> 
  <div class="page-header"> 
  </div> 
  {% endfor %} 
    </div><!--span10--> 
   <div class="span4"> 
    <h5>我的购物车</h5><br/> 
      <table class="condensed-table"> 
       <tbody> 
       {% for item in cart.items %} 
        <tr> 
         <th>{{item.quantity}}x</th> 
         <td>{{item.product.title}}</td> 
         <td>¥{% widthratio item.quantity 1 item.unit_price %} </td> 
        </tr> 
       {% endfor %} 
        <tr> 
         <td></td> 
         <th>总计:</th> 
         <th>¥{{cart.total_price|floatformat:"2"}}</th> 
        </tr> 
       </tbody> 
      </table> 
       
      <a class="btn danger" href="{% url depotapp.views.clean_cart %}">清空</a> 
      <a class="btn success" href="#">结算</a> 
    </div><!--span4--> 
  {% endblock %}

(2)在depotapp/views.py中的store_view视图函数中增加一行:

cart = request.session.get("cart",None)
就可以显示出如上的界面了。

2.编写javascript实现ajax
现在让我们来通过ajax请求后台服务。当然首选要实现后台服务。关于“加入购物车”,我们需要的服务是这样定义的:

url:    http://localhost:8000/depotapp/API/cart/items/post
post数据: product = product_id
处理过程: 根据product_id,将product加入购物车
返回:购物车中的所有条目
这个API的定义似乎不那么RESTful,但是暂且不去管它。实现这个服务需要为RESTful web service(depotapp/views.py中的RESTforCart类)增加一个方法:

def post(self, request, *args, **kwargs):
print request.POST['product']
product = Product.objects.get(id=request.POST['product'])
cart = request.session['cart']
cart.add_product(product)
request.session['cart'] = cart
return request.session['cart'].items

可以通过http://localhost:8000/depotapp/API/cart/items/post来测试服务接口(使用Firebug调试是非常方便的办法):

使用Python的Django框架结合jQuery实现AJAX购物车页面

如同你看到的那样,我们的接口定义不是完全RESTful,在生成的表单中,我们只需要选择Product,不用管另外的两个表单项,POST之后就可以从之前实现的购物车界面中看到新增加的产品项了。

服务接口测试通过,就可以在界面中通过ajax调用了。jquery对ajax提供了丰富的支持,为了方便使用jquery的selector,先要对html进行改造。将上面实现的depot/templates/depotapp/store.html中,迭代产品的部分改成如下的样子:

{% for item in products %}
<divclass="row"style="padding-top:10">
<divclass="span3 media-grid">
<ahref="#">
<imgclass="thumbnail"src="{{item.image_url}}"alt="">
</a>
</div>
<divclass="span6">
<h3>{{item.title}}</h3>
<br/>
{{item.description}}
<br/>
<br/>
<br/>
<divclass="row">
<divclass="span2"><h3>¥{{item.price|floatformat:"2"}}</h3></div>
<divclass="span"><aclass="btn primary"productid="{{item.id}}"href="#">加入购物车</a></div>
</div>
</div>
</div>
<divclass="page-header">
</div>
{% endfor %}

其中主要更改了“加入购物车”的<a>标签,增加productid属性,并将href改为“#”。这样我们就可以很方便的为其添加事件:

//store.html on ready
$('a.btn[productid]').bind("click",function(){
alert($(this).attr("productid"));
}
);

这段代码实现的功能是:对于所有的标签<a>,如果class包括“btn”,并且拥有“productid”属性的元素,添加click事件,弹出对话框显示其“productid”属性值。

打开产品清单界面测试一下,能够正确弹出产品ID,然后就可以编写ajax的处理了。在这里我们使用jquery.post()方法,jquery.post()是jquery.ajax的简化写法,如下:

//store.html on ready
$('a.btn[productid]').bind("click",function(){
var product_id=$(this).attr("productid");
//alert(product_id);
$.post("/depotapp/API/cart/items/post",
{product:product_id},
function(data){
alert(data);
}
);
}
);

弹出对话框显示的data就是前面定义的API接口的返回值,即现有购物车中的条目列表。

最后,要根据返回的数据更改界面上的购物车显示。这里为了方便也对html进行了改造。整个完成的depot/templates/depotapp/store.html如下:

{% extends "base.html" %}
{% block title %} 产品目录 {% endblock %}
{% block pagename %} 产品目录 {% endblock %}
{% block content %}
<divclass="row">
<divclass="span10">
{% for item in products %}
<divclass="row"style="padding-top:10">
<divclass="span3 media-grid">
<ahref="#">
<imgclass="thumbnail"src="{{item.image_url}}"alt="">
</a>
</div>
<divclass="span6">
<h3>{{item.title}}</h3>
<br/>
{{item.description}}
<br/>
<br/>
<br/>
<divclass="row">
<divclass="span2"><h3>¥{{item.price|floatformat:"2"}}</h3></div>
<divclass="span"><aclass="btn primary"productid="{{item.id}}"href="#">加入购物车</a></div>
</div>
</div>
</div>
<divclass="page-header">
</div>
{% endfor %}
</div><!--span10-->
<divclass="span4">
<h5>我的购物车</h5><br/>
<tableid="tabCart"class="condensed-table">
<tbodyid="items">
</tbody>
<tfoot>
<tr>
<td></td>
<th>总计:</th>
<tdid="totalprice">¥{{cart.total_price|floatformat:"2"}}</td>
</tr>
</tfoot>
</table>
<aclass="btn danger"href="{% url depotapp.views.clean_cart %}">清空</a>
<aclass="btn success"href="#">结算</a>
</div><!--span4-->
{% endblock %}
{% block js %}
<!--js from store.html-->
<script>
function refreshCart(items){
total = 0;
var tbody = $('tbody#items')[0];
tbody.innerHTML = "";
for(var i=0;i<items.length;i++){
total+=items[i].quantity*items[i].unit_price;
$('table#tabCart').append('<tr><td>'+items[i].quantity+'x</td>'+
'<td>'+items[i].product+'</td><td>¥'+items[i].unit_price+
'</td></tr>');
}
$('#totalprice')[0].innerHTML = '$'+total;
}
</script>
{% endblock %}
{% block on_ready %}
//store.html on ready
$.getJSON('/depotapp/API/cart/items/',refreshCart);
$('a.btn[productid]').bind("click",function(){
var product_id=$(this).attr("productid");
//alert(product_id);
$.post("/depotapp/API/cart/items/post",{product:product_id},refreshCart);
}
);
{% endblock %}

定义了一个refreshCart函数,根据参数”重绘“购物车界面。在$(document).ready部分,首先调用前面实现的API显示购物车,这样我们在模板中就可以去掉原来实现的”购物车“,改成javascript的方式。

然后为每个”加入购物车“按钮添加点击事件,调用本节开始部分实现的接口,根据返回的最新条目数据调用refreshCart函数重绘购物车。

上面的模板中,javascript的部分划分成了两个block:{% block js %}用于嵌入具体页面(相对应父模板)的js函数;{% block on_ready %}用于嵌入具体页面的$(document).ready处理。结合base.html中定义的block,可以使组合在一起的具体页面和模板页面符合Unobtrusive JavaScript 。这样做应该是Django+jquery实现ajax的最佳实践。

 

 

Python 相关文章推荐
python实现查询苹果手机维修进度
Mar 16 Python
使用Python实现一个简单的项目监控
Mar 31 Python
Python字符串逐字符或逐词反转方法
May 21 Python
python控制台中实现进度条功能
Nov 10 Python
Python正则抓取新闻标题和链接的方法示例
Apr 24 Python
python进行文件对比的方法
Dec 24 Python
python变量赋值方法(可变与不可变)
Jan 12 Python
用Python爬取QQ音乐评论并制成词云图的实例
Aug 24 Python
Python绘图实现显示中文
Dec 04 Python
Python类中的装饰器在当前类中的声明与调用详解
Apr 15 Python
Python控制台实现交互式环境执行
Jun 09 Python
详解python的xlwings库读写excel操作总结
Feb 26 Python
Python的Django REST框架中的序列化及请求和返回
Apr 11 #Python
python中的错误处理
Apr 10 #Python
python脚本实现xls(xlsx)转成csv
Apr 10 #Python
Python使用gensim计算文档相似性
Apr 10 #Python
Python调用SQLPlus来操作和解析Oracle数据库的方法
Apr 09 #Python
python调用fortran模块
Apr 08 #Python
python3使用urllib模块制作网络爬虫
Apr 08 #Python
You might like
我的论坛源代码(一)
2006/10/09 PHP
php加水印的代码(支持半透明透明打水印,支持png透明背景)
2013/01/17 PHP
php读取csv实现csv文件下载功能
2013/12/18 PHP
CodeIgniter中使用cookie的三种方式详解
2014/07/18 PHP
phpStudy访问速度慢和启动失败的解决办法
2015/11/19 PHP
php微信开发接入
2016/08/27 PHP
通过PHP设置BugFree获取邮箱通知
2019/04/25 PHP
jQuery编写widget的一些技巧分享
2010/10/28 Javascript
lyhucSelect基于Jquery的Select数据联动插件
2011/03/29 Javascript
关于js类的定义
2011/06/28 Javascript
jquery动画3.创建一个带遮罩效果的图片走廊
2012/08/24 Javascript
javascript实现十六进制颜色值(HEX)和RGB格式相互转换
2014/06/20 Javascript
jQuery实现不断闪烁文字的方法
2015/05/15 Javascript
JS+CSS实现仿支付宝菜单选中效果代码
2015/09/25 Javascript
Node.js环境下编写爬虫爬取维基百科内容的实例分享
2016/06/12 Javascript
BootStrap 智能表单实战系列(二)BootStrap支持的类型简介
2016/06/13 Javascript
Element input树型下拉框的实现代码
2018/12/21 Javascript
在Node.js中将SVG图像转换为PNG,JPEG,TIFF,WEBP和HEIF格式的方法
2019/08/22 Javascript
vue cli3.0打包上线静态资源找不到路径的解决操作
2020/08/03 Javascript
ES6字符串的扩展实例
2020/12/21 Javascript
Django中模型Model添加JSON类型字段的方法
2015/06/17 Python
python处理html转义字符的方法详解
2016/07/01 Python
python实现上传下载文件功能
2020/11/19 Python
Python实现找出数组中第2大数字的方法示例
2018/03/26 Python
Python反射和内置方法重写操作详解
2018/08/27 Python
python读取并定位excel数据坐标系详解
2019/06/26 Python
Python爬虫学习之获取指定网页源码
2019/07/30 Python
Linux下升级安装python3.8并配置pip及yum的教程
2020/01/02 Python
附答案的Java面试题
2012/11/19 面试题
迟到检讨书500字
2014/02/05 职场文书
十周年庆典策划方案
2014/06/03 职场文书
未受刑事制裁公证证明
2014/09/20 职场文书
教师作风建设剖析材料
2014/10/11 职场文书
夫妻分居协议书范本
2014/11/28 职场文书
党员个人总结自评
2015/02/14 职场文书
2016年教师党员公开承诺书
2016/03/24 职场文书