(转)Django ====> 实战学习篇十二 提交订单;自定义many-to-many关系,实现Atom订阅
原文转载地址:http://blog.csdn.net/thinkinside/article/details/7240914
源代码下载地址:留言写下邮箱地址,一天内会发送给你全部源代码
小结:
- 通过对实战系列文章进行总结,前边的内容已经基本涵盖了django开发的主要内容:
- 从需求界面设计开始,创建模型,修改模板,通过scaffold作为开发的起点;
- 在其基础之上重新定制模板,然后通过对model和form的两个类对用户输入数据进行校验;
- 涉及到了单元测试???为了提高用户界面开发的效率,更好的实现模板,讨论了对静态资源的管理(css,js,image等);
- 并且通过模板继承的方式实现了整个站点的统一布局;
- 作为web应用必不可少的session,演示了如何实现会话;
- 最后,在这些的基础之上增加了RESTful web service,将jquery集成到django,并且实现了ajax;
- 有了这些就足以应对django的开发绝大数问题了。
提交订单功能实现:
- 功能:买方点击“结算”,输入姓名地址等信息,发给卖方一张订单,订单包含买方信息和购物车条目;
- model类实现:即增加一个订单类(Order),修改原来的条目(Lineitem),增加到Order的外键,如下:外键就是一个manytoone的one小条目:
class Order(models.Model): name = models.CharField(max_length=50) address = models.TextField() email = models.EmailField() class LineItem(models.Model): product = models.ForeignKey(Product) order = models.ForeignKey(Order) unit_price = models.DecimalField(max_digits=8,decimal_places=2) quantity = models.IntegerField()
- 通过scaffold生成一系列丑陋的界面:生成之前一定要备份depotapp下的form urls views ,生成之后进行手工合并,切记。
- 将模板中的结算标签链接改为映射到生成create_order视图函数:
<a class="btn success" href="{% url depotapp.views.create_order %}">结算</a> depot/templates/depotapp/store.html
- 这样两个界面已经链接起来了,自动生成的订单有一下几点:
- 没有将session中的条目保存到数据库中
- 也没有清空购物车
- 没有提交之后跳转回产品目录界面
- 上边提到的问题都需要解决,主要的修改在creat_order视图函数中,原始视图函数如下:
def create_order(request): form = OrderForm(request.POST or None) if form.is_valid(): form.save() form = OrderForm() t = get_template('depotapp/create_order.html') c = RequestContext(request,locals()) return HttpResponse(t.render(c))
- 关于事务处理:保存订单和保存订单条目应该形成一个事务,事务处理可以通过middleware添加,也可以手工添加,手工添加方式更加灵活,通过在view函数前增加修饰符来实现,三种修饰符可以选择:
@transaction.autocommint 在save()或者delete()的时候自动提交事务 @transaction.commit_on_success 整个view成功后提交事务,否则回滚 @transaction.commit_manually 手动调用commit或rollback
- 暂时不使用middleware的方式,所以用 @transaction.commit_on_success 实现事务处理,需要引用transaction模块,fromdjango.db import transaction
- 最终修改的提交订单creat_order view函数如下:
@transaction.commit_on_success def create_order(request): form = OrderForm(request.POST or None) if form.is_valid(): order = form.save() for item in request.session['cart'].items: item.order = order item.save() clean_cart(request) return store_view(request) t = get_template('depotapp/create_order.html') c = RequestContext(request,locals()) return HttpResponse(t.render(c))
自定义many-to-many关系,实现Atom订阅:
- 在django中,many-to-many关系表是自己建立的,如果要指定一个自己的model类作为关系对象,只需要在制定的对端model类中增加一个ManyToManyField属性,并且制定through参数;
- 比如现在我们已经有了两个manytoone关系:order---lineitem , product---lineitem,要通过从product直接获取关系的order只需要增加一行:
orders = models.ManyToManyField(Order, through='LineItem')
通过product直接找到包含该产品的订单:
[shishang@shishang depot]$ python manage.py shell Python 2.7.3 (default, Jul 24 2012, 10:05:39) [GCC 4.7.0 20120507 (Red Hat 4.7.0-5)] on linux2 Type "help", "copyright", "credits" or "license" for more information. (InteractiveConsole) >>> from depotapp.models import Product >>> p = Product(id=1) >>> p <Product: > >>> p.orders <django.db.models.fields.related.ManyRelatedManager object at 0x932278c> >>> p.orders.all() [<Order: 石尚>, <Order: shishang>]
- 实现这个关系的主要目的是我们要针对每个产品生成一个“订阅”,用于查看谁买了该商品,采用Atom作为格式的标准,生成的Atom发布格式如下:
<?xml version="1.0" encoding="UTF-8"?> <feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom"> <id>tag:localhost,2005:/products/3/who_bought</id> <link type="text/html" href="http://localhost:3000/depotapp" rel="alternate"/> <link type="application/atom+xml" href="http://localhost:8000/depotapp/product/3/who_bought" rel="self"/> <title>谁购买了《黄瓜的黄 西瓜的西》</title> <updated>2012-01-02 12:02:02</updated> <entry> <id>tag:localhost,2005:Order/1</id> <published>2012-01-02 12:02:02</published> <updated>2012-01-02 12:02:02</updated> <link rel="alternate" type="text/html" href="http://localhost:8000/orders/1"/> <title>订单1</title> <summary type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>我住在北京</p> </div> </summary> <author> <name>我是买家</name> <email>wanghaikuo@gmail.com</email> </author> </entry> <entry> <id>tag:localhost,2005:Order/3</id> <published>2012-01-02 12:02:02</published> <updated>2012-01-02 12:02:02</updated> <link rel="alternate" type="text/html" href="http://localhost:8000/orders/3"/> <title>订单3</title> <summary type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>我住在哪里?</p> </div> </summary> <author> <name>我是买家2</name> <email>2222b@baidu.com</email> </author> </entry> </feed>
- Atom 是XML为格式的,可以借助RESTful实现,但是不是一个好主意,应为RESTful有自身的xml格式,与Atom的格式完全不同,如果使用RESTful就要对其进行定制,实现一个自己的render,这需要深入了解该框架的大量细节,为了简单起见,考虑使用django模板实现;
- 首先设计url,加入urlpatterns:
(r'product/(?P<id>[^/]+)/who_bought', atom_of_order),
- 视图函数中实现atom_of_order:
def atom_of_order(request,id): product = Product.objects.get(id = id) t = get_template('depotapp/atom_order.xml') c=RequestContext(request,locals()) return HttpResponse(t.render(c), mimetype='application/atom+xml') mimetype指定了mimetype使浏览器知道返回的是xml而不是html
- 最后实现模板:/depot/templates/depotapp/atom_order.xml:
<?xml version="1.0" encoding="UTF-8"?> <feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom"> <id>tag:localhost,2005:/product/{{product.id}/who_bought</id> <link type="text/html" href="{% url depotapp.views.store_view %}" rel="alternate"/> <link type="application/atom+xml" href="{% url depotapp.views.atom_of_order product.id %}" rel="self"/> <title>谁购买了《{{product.title}}》</title> <updated>2012-01-02 12:02:02</updated> {% for order in product.orders.all %} <entry> <id>tag:localhost,2005:order/{{order.id}}</id> <published>2012-01-02 12:02:02</published> <updated>2012-01-02 12:02:02</updated> <link rel="alternate" type="text/html" href="{% url depotapp.views.atom_of_order order.id %}"/> <title>订单{{order.id}}</title> <summary type="xhtml"> <div xmlns="http://www.w3.org/1999/xhtml"> <p>{{order.address}}</p> </div> </summary> <author> <name>{{order.name}}</name> <email>{{order.email}}</email> </author> </entry> {% endfor %} </feed>
- 用模板实现Atom发布,其实很简单。
“某度”空间 http://hi.baidu.com/new/wenjiashe521
cnblogs空间 http://www.cnblogs.com/wenjiashe521/