(转)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发布,其实很简单。
posted @ 2012-11-27 15:00  事件轮询,回不到过去  阅读(570)  评论(0编辑  收藏  举报