創(chuàng)新互聯(lián)www.cdcxhl.cn八線動(dòng)態(tài)BGP香港云服務(wù)器提供商,新人活動(dòng)買多久送多久,劃算不套路!

這篇文章將為大家詳細(xì)講解有關(guān)django訂單模塊的實(shí)現(xiàn)方法,小編覺得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
Django設(shè)計(jì)的訂單相關(guān)的表如下所示:

由于每一個(gè)訂單中的商品種類與數(shù)量都不定,因此單獨(dú)將訂單商品提出為一個(gè)表,為一對(duì)多的關(guān)系。
訂單的提交
從購物車頁面提交是通過form形式提交的,在checkbox元素中定義參數(shù)value并設(shè)為對(duì)應(yīng)的商品id,則傳遞到后端的為一個(gè)由選中商品id組成的列表,在后端中的業(yè)務(wù)流程為:
①獲取參數(shù)并校驗(yàn),表單中的checkbox只有被選中時(shí)其value才會(huì)被提交,若不選中則不提交,若有多個(gè)name相同,則使用POST.getlist獲取到一個(gè)由多個(gè)value(checkbox的value)組成的列表;
②從redis中獲取該用戶購物車的信息,從mysql中獲取商品id對(duì)應(yīng)的信息,計(jì)算數(shù)量與總價(jià)格,并將其動(dòng)態(tài)添加到查詢到的sku模型類實(shí)例中;
③處理運(yùn)費(fèi)與實(shí)付款;
④組織參數(shù),渲染訂單創(chuàng)建的頁面。
訂單的提交并不復(fù)雜,其中重點(diǎn)在于如何將選中的商品id傳入后端,以及傳入訂單創(chuàng)建頁面的參數(shù)選擇。
訂單的創(chuàng)建
訂單創(chuàng)建的前端頁面
共分為三部分:
①收貨地址的選擇,此處將默認(rèn)收貨地址默認(rèn)選中,可以在該用戶已有的收貨地址中選擇,也可以跳轉(zhuǎn)到收貨地址的編輯頁面;
②支付方式的選擇,因?yàn)榇颂幹蛔隽酥Ц秾毜慕涌谝虼似渌Ц斗绞綍簳r(shí)無法支付,但是可以提交;
③將要提交的商品按條目顯示(在訂單提交后端中傳入),并顯示其數(shù)量、單價(jià)、小計(jì)、單位等信息,顯示總價(jià)、運(yùn)費(fèi)、總數(shù)量信息;
注:①在訂單創(chuàng)建頁面不使用form進(jìn)行post提交,使用ajax post提交,訂單創(chuàng)建成功時(shí)跳轉(zhuǎn)到訂單頁面,創(chuàng)建失敗時(shí)不跳轉(zhuǎn),顯示后端傳遞的具體信息;
②由于訂單中的信息是從購物車中查詢到的,這個(gè)信息可能與真實(shí)情況不符(如商品下架,庫存賣完等),因此在訂單創(chuàng)建時(shí)必須要進(jìn)行多次校驗(yàn)之后才可以確定訂單是否可以創(chuàng)建成功。
訂單創(chuàng)建的參數(shù)傳遞
從購物車提交至訂單創(chuàng)建頁面再到訂單創(chuàng)建后端,其傳遞選中的商品都是通過傳遞sku_id然后通過查詢r(jià)edis中的用戶購物車信息來進(jìn)行的(并不直接傳遞具體的商品信息),但由于訂單創(chuàng)建功能不與購物車頁面交互,因此將被選中商品的sku_ids重構(gòu)為一個(gè)字符串,直接從購物車傳遞到訂單創(chuàng)建頁面,并在訂單創(chuàng)建頁面中動(dòng)態(tài)添加一個(gè)屬性為sku_ids(此方法常用于在頁面中獲取變量)并使用ajax post請(qǐng)求發(fā)回后端,在訂單創(chuàng)建流程中使用。
訂單創(chuàng)建的注意事項(xiàng)
(1)關(guān)于訂單提交失敗:由于可能因?yàn)楦鞣N原因?qū)е碌挠唵螣o法完成,但訂單記錄會(huì)在數(shù)據(jù)庫中生成,因此使用mysql事務(wù)來對(duì)訂單提交(即把在兩個(gè)表中的創(chuàng)建打包為一組事務(wù),不允許出現(xiàn)空訂單的情況);
(2)關(guān)于并發(fā)訂單的處理:
①悲觀鎖:在某一條ORM查詢語句上加鎖(objects.select_for_update()),則多個(gè)用戶同時(shí)進(jìn)行訂單提交時(shí),哪個(gè)線程先執(zhí)行到該語句則獲取鎖,待事務(wù)結(jié)束后才會(huì)釋放,其他線程在執(zhí)行至此時(shí)阻塞等待獲取鎖,保證了同一時(shí)刻只有一個(gè)事務(wù)在運(yùn)行;
②樂觀鎖:查詢時(shí)不加鎖,在變更時(shí)對(duì)比原數(shù)據(jù)與當(dāng)前重新查詢的數(shù)據(jù),若不一致則失敗(即樂觀的認(rèn)為當(dāng)前沒有其他線程在同時(shí)進(jìn)行此過程),一般采用3次循環(huán)重復(fù)此過程,但由于數(shù)據(jù)庫事務(wù)的隔離性,查詢到的原數(shù)據(jù)可能不會(huì)更新,因此需要修正數(shù)據(jù)庫事務(wù)隔離的級(jí)別為read committed(在Django2.0版本中已經(jīng)自動(dòng)將所有數(shù)據(jù)庫的事務(wù)隔離級(jí)別修改為read-committed,因此無需專門修改mysql數(shù)據(jù)庫隔離級(jí)別),此時(shí)樂觀鎖可執(zhí)行;
③使用方式:在沖突較少時(shí)使用樂觀鎖(省去加鎖、釋放鎖的開銷,提高性能),在沖突較多時(shí)使用悲觀鎖(省去大量無用的循環(huán)),且若樂觀鎖重復(fù)操作的代價(jià)比較大也選用悲觀鎖。
注:一般將整個(gè)事務(wù)的過程都放置于try中。
訂單創(chuàng)建的后端流程
①校驗(yàn)參數(shù);
②添加事務(wù),在事務(wù)中進(jìn)行樂觀/悲觀鎖設(shè)置,創(chuàng)建訂單模型類實(shí)例,通過傳入的sku_ids在redis購物車中進(jìn)行查詢,查詢到sku商品實(shí)例后操作庫存值并添加訂單商品實(shí)例;
③重復(fù)②中對(duì)sku_ids的操作,對(duì)所有選中的商品都進(jìn)行此操作,其中在操作失效、校驗(yàn)失敗時(shí)需要進(jìn)行回滾,操作成功后更新訂單模型類實(shí)例的內(nèi)容并提交;
④清空用戶購物車中已提交的記錄,提交事務(wù),并返回應(yīng)答,當(dāng)創(chuàng)建成功時(shí)跳轉(zhuǎn)到個(gè)人訂單頁面,創(chuàng)建失敗時(shí)提示錯(cuò)誤信息。
class OrderCommitView(View):
'''訂單提交創(chuàng)建'''
@transaction.atomic
def post(self, request):
# 判斷用戶是否登錄
user = request.user
if not user.is_authenticated:
return JsonResponse({'res':0, 'errmsg':'請(qǐng)先登錄'})
# 獲取參數(shù)
addr_id = request.POST.get('addr_id')
pay_method = int(request.POST.get('pay_method'))
sku_ids = request.POST.get('sku_ids')
# 校驗(yàn)參數(shù)
if not all([addr_id, pay_method, sku_ids]):
return JsonResponse({'res':1, 'errmsg':'數(shù)據(jù)不完整'})
# 校驗(yàn)支付方式
if pay_method not in OrderInfo.PAY_METHOD.keys():
print(pay_method, type(pay_method))
return JsonResponse({'res':2, 'errmsg':'非法的支付方式'})
# 校驗(yàn)地址
try:
addr = Address.objects.get(id=addr_id)
except Address.DoesNotExist:
return JsonResponse({'res':3, 'errmsg':'地址不存在'})
# 創(chuàng)建訂單核心業(yè)務(wù)
# 創(chuàng)建訂單信息缺少的內(nèi)容
# 訂單ID,使用年月日時(shí)分秒+用戶ID創(chuàng)建訂單編號(hào)
order_id = datetime.now().strftime('%Y%m%d%H%M%S')+str(user.id)
# 運(yùn)費(fèi)
transit_price = 10
# 總數(shù)目和總金額,添加記錄,先使用默認(rèn)值,后續(xù)修改
total_count = 0
total_price = 0
# 添加數(shù)據(jù)庫事務(wù)的保存點(diǎn)
save_id = transaction.savepoint()
try:
# 向訂單信息表中添加記錄
order = OrderInfo.objects.create(order_id=order_id,
user=user,
addr=addr,
pay_method=pay_method,
transit_price=transit_price,
total_price=total_price,
total_count=total_count)
if order.pay_method == 1:
order.order_status = 2
# 獲取訂單商品表的參數(shù)
conn = get_redis_connection('default')
cart_key = 'cart_{}'.format(user.id)
sku_ids = sku_ids.split(',')
for sku_id in sku_ids:
for i in range(3):
try:
sku = GoodsSKU.objects.get(id=sku_id)
except GoodsSKU.DoesNotExist:
# 回滾到保存點(diǎn),此處的回滾是為了撤銷已創(chuàng)建的表
transaction.savepoint_rollback(save_id)
return JsonResponse({'res':4, 'errmsg':'商品不存在'})
# 獲取商品的數(shù)量
count = conn.hget(cart_key, sku_id)
# 校驗(yàn)庫存值
if int(count)>sku.stock:
# 回滾到保存點(diǎn)
transaction.savepoint_rollback(save_id)
return JsonResponse({'res':5, 'errmsg':'商品庫存不足'})
# 保存原庫存與新庫存
origin_stock = sku.stock
new_stock = origin_stock - int(count)
new_sales = sku.sales + int(count)
print('user:{} times:{} stock:{}'.format(user.id, i, sku.stock))
# 返回受影響的行數(shù),0/1
res = GoodsSKU.objects.filter(id=sku_id, stock=origin_stock).update(stock=new_stock, sales=new_sales)
if res == 0:
if i == 2:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res':7, 'errmsg':'訂單創(chuàng)建失敗'})
continue
# 向訂單商品表中添加記錄,由于此處并沒有設(shè)置保存點(diǎn),因此將判斷放在添加記錄的前面,防止重復(fù)添加
OrderGoods.objects.create(order=order,
sku=sku,
count=count,
price=sku.price)
# 更新相關(guān)商品的銷量和庫存
sku.stock -= int(count)
sku.sales += int(count)
sku.save()
# 計(jì)算訂單商品的總數(shù)量和總價(jià)格
amount = sku.price*int(count)
total_count += int(count)
total_price += amount
break
# 更新訂單詳情表中的總數(shù)量和總價(jià)格
order.total_count = total_count
order.total_price = total_price
order.save()
# 清除用戶購物車中的記錄
conn.hdel(cart_key, *sku_ids)
except Exception:
transaction.savepoint_rollback(save_id)
return JsonResponse({'res':7, 'errmsg':'訂單創(chuàng)建失敗'})
# 提交事務(wù),返回應(yīng)答
transaction.savepoint_commit(save_id)
return JsonResponse({'res':6, 'message':'訂單創(chuàng)建成功'}) 訂單的顯示
訂單顯示在個(gè)人中心中,根據(jù)用戶從訂單模型類中取出所有的訂單實(shí)例,再根據(jù)每個(gè)訂單實(shí)例從訂單商品類中取出對(duì)應(yīng)的商品(此處不從sku商品表中取,因?yàn)橛唵翁峤粫r(shí)的價(jià)格與當(dāng)前價(jià)格可能不同),計(jì)算小計(jì)并動(dòng)態(tài)添加屬性,然后進(jìn)行分頁,對(duì)分頁對(duì)象進(jìn)行處理。
注:①操作與商品列表分頁類似,對(duì)于訂單的排序此處略過,默認(rèn)按照創(chuàng)建時(shí)間進(jìn)行排序;
②在前端中,根據(jù)用戶訂單的支付狀態(tài)和支付方式確定提供給用戶的按鈕文字,并根據(jù)支付狀態(tài)來判斷點(diǎn)擊時(shí)進(jìn)行的邏輯(去支付/去評(píng)論)。
訂單的支付
此處調(diào)用支付寶的測(cè)試接口進(jìn)行支付,關(guān)于支付寶接口的調(diào)用詳情可參支付寶沙箱環(huán)境開發(fā)文檔.
訂單支付結(jié)果的查詢
如上圖所示,支付寶在支付結(jié)果產(chǎn)生后會(huì)向網(wǎng)站返回支付結(jié)果,但可能由于網(wǎng)絡(luò)原因并不準(zhǔn)確,因此主動(dòng)去調(diào)用支付寶接口查詢支付狀態(tài),在引導(dǎo)用戶去支付頁面之后就發(fā)起ajax post請(qǐng)求用于獲取支付結(jié)果,循環(huán)調(diào)用支付寶接口進(jìn)行查詢(此接口的返回值中包括等待用戶付款),若支付成功則更改訂單支付狀態(tài)并返回,若支付失敗則返回錯(cuò)誤信息。
注:訂單的支付是由用戶與支付寶交互完成的,網(wǎng)站服務(wù)器不參與,網(wǎng)站服務(wù)器只負(fù)責(zé)提供支付鏈接與查詢支付結(jié)果,通過支付寶的返回狀態(tài)來對(duì)當(dāng)前用戶訂單狀態(tài)進(jìn)行更改。
商品評(píng)論
①評(píng)論頁面顯示:當(dāng)訂單支付成功,直接跳轉(zhuǎn)到商品評(píng)論頁面,商品評(píng)論頁面中單個(gè)訂單的多個(gè)商品都有自己的評(píng)論框,使用form表單的形式進(jìn)行提交。
注:由于有多個(gè)商品,而顯示的時(shí)候是循環(huán)顯示,因此使用forloop.counter給商品和評(píng)論框起名,這樣可以對(duì)它們進(jìn)行綁定,避免混淆。
②評(píng)論內(nèi)容提交:如上所述,在后端中獲取提交的評(píng)論內(nèi)容并將其添加到訂單商品類中,更改訂單狀態(tài),訂單完成,重定向到訂單頁面。
注:由于一個(gè)訂單中的商品可能有的評(píng)價(jià)有的不評(píng)價(jià),會(huì)造成訂單狀態(tài)的不確定,因此可以設(shè)置若不評(píng)價(jià)則給出默認(rèn)值或評(píng)論框不允許為空,即只要點(diǎn)擊進(jìn)入評(píng)論頁面,無論如何處理只要邏輯完成則更改訂單狀態(tài)為已完成。
關(guān)于django訂單模塊的實(shí)現(xiàn)方法就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,可以學(xué)到更多知識(shí)。如果覺得文章不錯(cuò),可以把它分享出去讓更多的人看到。
分享題目:django訂單模塊的實(shí)現(xiàn)方法-創(chuàng)新互聯(lián)
網(wǎng)站網(wǎng)址:http://chinadenli.net/article10/dsjido.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、面包屑導(dǎo)航、動(dòng)態(tài)網(wǎng)站、企業(yè)網(wǎng)站制作、電子商務(wù)、小程序開發(fā)
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容