前面的內容已經基本上涵蓋了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))