使用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多线程编程(四):使用Lock互斥锁
Apr 05 Python
详解Python中的Descriptor描述符类
Jun 14 Python
Python编程修改MP3文件名称的方法
Apr 19 Python
python基础教程项目四之新闻聚合
Apr 02 Python
python3下实现搜狗AI API的代码示例
Apr 10 Python
在Pycharm中对代码进行注释和缩进的方法详解
Jan 20 Python
selenium+python自动化测试之使用webdriver操作浏览器的方法
Jan 23 Python
简单介绍python封装的基本知识
Aug 10 Python
在django中使用apscheduler 执行计划任务的实现方法
Feb 11 Python
VS2019+python3.7+opencv4.1+tensorflow1.13配置详解
Apr 16 Python
使用sklearn对多分类的每个类别进行指标评价操作
Jun 11 Python
详解matplotlib中pyplot和面向对象两种绘图模式之间的关系
Jan 22 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
用php过滤危险html代码的函数
2008/07/22 PHP
PHP 函数学习简单小结
2010/07/08 PHP
php获取中文拼音首字母类和函数分享
2014/04/24 PHP
php数组中包含中文的排序方法
2014/06/03 PHP
ThinkPHP框架下微信支付功能总结踩坑笔记
2019/04/10 PHP
php的命名空间与自动加载实现方法
2019/08/25 PHP
在一个form用一个SUBMIT(或button)分别提交到两个处理表单页面的代码
2007/02/15 Javascript
javascript 获取表单file全路径
2009/12/31 Javascript
xss文件页面内容读取(解决)
2010/11/28 Javascript
jQuery之网页换肤实现代码
2011/04/30 Javascript
JQuery1.6 使用方法三
2011/11/23 Javascript
jQuery学习笔记之控制页面实现代码
2012/02/27 Javascript
jquery 实现checkbox全选,反选,全不选等功能代码(奇数)
2012/10/24 Javascript
UpdatePanel和Jquery冲突的解决方法
2013/04/01 Javascript
原生Js页面滚动延迟加载图片实现原理及过程
2013/06/24 Javascript
JS画5角星方法介绍
2013/09/17 Javascript
JS实现自适应高度表单文本框的方法
2015/02/25 Javascript
Angularjs CURD 详解及实例代码
2016/09/14 Javascript
bootstrap paginator分页插件的两种使用方式实例详解
2017/11/14 Javascript
简述pm2常用命令集合及配置文件说明
2019/05/30 Javascript
[46:37]LGD vs TNC 2019国际邀请赛小组赛 BO2 第二场 8.15
2019/08/16 DOTA
Python处理XML格式数据的方法详解
2017/03/21 Python
解决安装pycharm后不能执行python脚本的问题
2019/01/19 Python
使用python绘制二元函数图像的实例
2019/02/12 Python
django-crontab实现服务端的定时任务的示例代码
2020/02/17 Python
python3中布局背景颜色代码分析
2020/12/01 Python
CSS3实现div从下往上滑入滑出效果示例
2020/04/28 HTML / CSS
详解HTML5 data-* 自定义属性
2018/01/24 HTML / CSS
美国在线自行车商店:Jenson USA
2018/05/22 全球购物
远程研修随笔感言
2014/02/10 职场文书
党员干部公开承诺书
2014/03/26 职场文书
党的群众路线教育实践活动个人整改方案
2014/10/25 职场文书
接待员岗位职责范本
2015/04/15 职场文书
2015年乡镇党务公开工作总结
2015/05/19 职场文书
Mysql案例刨析事务隔离级别
2021/09/25 MySQL
Python 匹配文本并在其上一行追加文本
2022/05/11 Python