Django实战(18):提交订单
前面的内容已经基本上涵盖了Django开发的主要方面,我们从需求和界面设计出发,创建模型和修改模型,并通过scaffold作为开发的起点;在scaffold的基础上重新定制模板,并且通过Model类和Form类对用户输入的数据进行校验。我们也涉及到了单元测试。为了提高开发用户界面的效率,更好地实现模板,我们还讨论了对静态资源(css,js,image等)的管理,并通过模板继承的方式实现了整个站点的统一布局。作为web应用必不可少的部分,我们还演示了如何使用会话(session)。最后,我们还在这些基础上增加了RESTful web service,将jquery集成到Django,并实现了ajax。
有了这些基础,可以应付Django开发中的绝大多数问题。
下面我们继续实现depot购物车的web应用。本节要实现提交订单功能。现在买方已经可以挑选需要的产品放入购物车,但是还不能进行购买。我们希望实现这样的功能:
买方点击”结算“按钮,然后输入姓名、地址和email信息,就向卖方发出了一张订单,该订单包含上述买方信息和其选购的所有条目。首先还是实现Model类。我们要增加一个订单类(Order),并修改原来的条目类(LineItem),增加到Order的外键(即LineItem到Order的many-to-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()
要注意,因为LineItem引用了Order,所以在定义模型类的顺序上要将Order放在前面。
前面介绍过修改模型类之后应该如何处理,这里就不再重复了。
然后祭出scaffold,快速生成一系列”丑陋“的界面。该工具还不够成熟,在生成之前,一定要备份depotapp/urls.py 、views.py 和 forms.py,之后手工合并,切记!
之后将产品目录界面(depot/templates/depotapp/store.html)中的”结算“标签的链接改为映射到生成的create_order视图函数:
- <aclass="btn success"href="{% url depotapp.views.create_order %}">结算</a>
两 个界面就链接起来了。但是自动生成的订单界面并没有将session中的条目保存到数据库,也没有清空购物车,并且提交订单后没有返回到产品目录界面,所 以还要对其进行修改。主要的修改在create_order视图函数中进行。为了方便对比,将生成的原始视图函数列出如下:
- def create_order(request):
- form = OrderForm(request.POST orNone)
- if form.is_valid():
- form.save()
- form = OrderForm()
- t = get_template('depotapp/create_order.html')
- c = RequestContext(request,locals())
- return HttpResponse(t.render(c))
关于事务处理
”保存订单“和”保存订单条目“应该形成一个事务。Django的事务处理可以通过middleware自动添加,也可以手工添加。手工添加的方式更加灵活,通过在view函数前增加修饰符(decorator)来实现,有三种修饰符可以选择:
- @transaction.autocommit 在 save() 或 delete() 时自动提交事务。
- @transaction.commit_on_success 当整个view成功后提交事务,否则回滚( TransactionMiddleware采用的就是这种机制)
- @transaction.commit_manually 需要手动调用commit或rollback。
我们暂时不想使用middleware的方式,所以用@transaction.commit_on_success来实现事务管理。这需要引用transaction模块:from django.db import transaction
最终修改的create_order视图函数如下:
- @transaction.commit_on_success
- def create_order(request):
- form = OrderForm(request.POST orNone)
- 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))