django訂單模塊的實現(xiàn)方法-創(chuàng)新互聯(lián)

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

十載的高密網(wǎng)站建設(shè)經(jīng)驗,針對設(shè)計、前端、開發(fā)、售后、文案、推廣等六對一服務(wù),響應(yīng)快,48小時及時工作處理。網(wǎng)絡(luò)營銷推廣的優(yōu)勢是能夠根據(jù)用戶設(shè)備顯示端的尺寸不同,自動調(diào)整高密建站的顯示方式,使網(wǎng)站能夠適用不同顯示終端,在瀏覽器中調(diào)整網(wǎng)站的寬度,無論在任何一種瀏覽器上瀏覽網(wǎng)站,都能展現(xiàn)優(yōu)雅布局與設(shè)計,從而大程度地提升瀏覽體驗。成都創(chuàng)新互聯(lián)公司從事“高密網(wǎng)站設(shè)計”,“高密網(wǎng)站推廣”以來,每個客戶項目都認真落實執(zhí)行。

這篇文章將為大家詳細講解有關(guān)django訂單模塊的實現(xiàn)方法,小編覺得挺實用的,因此分享給大家做個參考,希望大家閱讀完這篇文章后可以有所收獲。

Django設(shè)計的訂單相關(guān)的表如下所示:

django訂單模塊的實現(xiàn)方法

由于每一個訂單中的商品種類與數(shù)量都不定,因此單獨將訂單商品提出為一個表,為一對多的關(guān)系。

訂單的提交

從購物車頁面提交是通過form形式提交的,在checkbox元素中定義參數(shù)value并設(shè)為對應(yīng)的商品id,則傳遞到后端的為一個由選中商品id組成的列表,在后端中的業(yè)務(wù)流程為:

①獲取參數(shù)并校驗,表單中的checkbox只有被選中時其value才會被提交,若不選中則不提交,若有多個name相同,則使用POST.getlist獲取到一個由多個value(checkbox的value)組成的列表;

②從redis中獲取該用戶購物車的信息,從mysql中獲取商品id對應(yīng)的信息,計算數(shù)量與總價格,并將其動態(tài)添加到查詢到的sku模型類實例中;

③處理運費與實付款;

④組織參數(shù),渲染訂單創(chuàng)建的頁面。

訂單的提交并不復(fù)雜,其中重點在于如何將選中的商品id傳入后端,以及傳入訂單創(chuàng)建頁面的參數(shù)選擇。

訂單的創(chuàng)建

訂單創(chuàng)建的前端頁面

共分為三部分:

①收貨地址的選擇,此處將默認收貨地址默認選中,可以在該用戶已有的收貨地址中選擇,也可以跳轉(zhuǎn)到收貨地址的編輯頁面;

②支付方式的選擇,因為此處只做了支付寶的接口因此其他支付方式暫時無法支付,但是可以提交;

③將要提交的商品按條目顯示(在訂單提交后端中傳入),并顯示其數(shù)量、單價、小計、單位等信息,顯示總價、運費、總數(shù)量信息;

注:①在訂單創(chuàng)建頁面不使用form進行post提交,使用ajax post提交,訂單創(chuàng)建成功時跳轉(zhuǎn)到訂單頁面,創(chuàng)建失敗時不跳轉(zhuǎn),顯示后端傳遞的具體信息;

②由于訂單中的信息是從購物車中查詢到的,這個信息可能與真實情況不符(如商品下架,庫存賣完等),因此在訂單創(chuàng)建時必須要進行多次校驗之后才可以確定訂單是否可以創(chuàng)建成功。

訂單創(chuàng)建的參數(shù)傳遞

從購物車提交至訂單創(chuàng)建頁面再到訂單創(chuàng)建后端,其傳遞選中的商品都是通過傳遞sku_id然后通過查詢redis中的用戶購物車信息來進行的(并不直接傳遞具體的商品信息),但由于訂單創(chuàng)建功能不與購物車頁面交互,因此將被選中商品的sku_ids重構(gòu)為一個字符串,直接從購物車傳遞到訂單創(chuàng)建頁面,并在訂單創(chuàng)建頁面中動態(tài)添加一個屬性為sku_ids(此方法常用于在頁面中獲取變量)并使用ajax post請求發(fā)回后端,在訂單創(chuàng)建流程中使用。

訂單創(chuàng)建的注意事項

(1)關(guān)于訂單提交失?。河捎诳赡芤驗楦鞣N原因?qū)е碌挠唵螣o法完成,但訂單記錄會在數(shù)據(jù)庫中生成,因此使用mysql事務(wù)來對訂單提交(即把在兩個表中的創(chuàng)建打包為一組事務(wù),不允許出現(xiàn)空訂單的情況);

(2)關(guān)于并發(fā)訂單的處理:

①悲觀鎖:在某一條ORM查詢語句上加鎖(objects.select_for_update()),則多個用戶同時進行訂單提交時,哪個線程先執(zhí)行到該語句則獲取鎖,待事務(wù)結(jié)束后才會釋放,其他線程在執(zhí)行至此時阻塞等待獲取鎖,保證了同一時刻只有一個事務(wù)在運行;

②樂觀鎖:查詢時不加鎖,在變更時對比原數(shù)據(jù)與當(dāng)前重新查詢的數(shù)據(jù),若不一致則失敗(即樂觀的認為當(dāng)前沒有其他線程在同時進行此過程),一般采用3次循環(huán)重復(fù)此過程,但由于數(shù)據(jù)庫事務(wù)的隔離性,查詢到的原數(shù)據(jù)可能不會更新,因此需要修正數(shù)據(jù)庫事務(wù)隔離的級別為read committed(在Django2.0版本中已經(jīng)自動將所有數(shù)據(jù)庫的事務(wù)隔離級別修改為read-committed,因此無需專門修改mysql數(shù)據(jù)庫隔離級別),此時樂觀鎖可執(zhí)行;

③使用方式:在沖突較少時使用樂觀鎖(省去加鎖、釋放鎖的開銷,提高性能),在沖突較多時使用悲觀鎖(省去大量無用的循環(huán)),且若樂觀鎖重復(fù)操作的代價比較大也選用悲觀鎖。

注:一般將整個事務(wù)的過程都放置于try中。

訂單創(chuàng)建的后端流程

①校驗參數(shù);

②添加事務(wù),在事務(wù)中進行樂觀/悲觀鎖設(shè)置,創(chuàng)建訂單模型類實例,通過傳入的sku_ids在redis購物車中進行查詢,查詢到sku商品實例后操作庫存值并添加訂單商品實例;

③重復(fù)②中對sku_ids的操作,對所有選中的商品都進行此操作,其中在操作失效、校驗失敗時需要進行回滾,操作成功后更新訂單模型類實例的內(nèi)容并提交;

④清空用戶購物車中已提交的記錄,提交事務(wù),并返回應(yīng)答,當(dāng)創(chuàng)建成功時跳轉(zhuǎn)到個人訂單頁面,創(chuàng)建失敗時提示錯誤信息。

class OrderCommitView(View):
	'''訂單提交創(chuàng)建'''
	@transaction.atomic
	def post(self, request):
		# 判斷用戶是否登錄
		user = request.user
		if not user.is_authenticated:
			return JsonResponse({'res':0, 'errmsg':'請先登錄'})
		# 獲取參數(shù)
		addr_id = request.POST.get('addr_id')
		pay_method = int(request.POST.get('pay_method'))
		sku_ids = request.POST.get('sku_ids')
		# 校驗參數(shù)
		if not all([addr_id, pay_method, sku_ids]):
			return JsonResponse({'res':1, 'errmsg':'數(shù)據(jù)不完整'})
		# 校驗支付方式
		if pay_method not in OrderInfo.PAY_METHOD.keys():
			print(pay_method, type(pay_method))
			return JsonResponse({'res':2, 'errmsg':'非法的支付方式'})
		# 校驗地址
		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,使用年月日時分秒+用戶ID創(chuàng)建訂單編號
		order_id = datetime.now().strftime('%Y%m%d%H%M%S')+str(user.id)
		# 運費
		transit_price = 10
		# 總數(shù)目和總金額,添加記錄,先使用默認值,后續(xù)修改
		total_count = 0
		total_price = 0
		# 添加數(shù)據(jù)庫事務(wù)的保存點
		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:
						# 回滾到保存點,此處的回滾是為了撤銷已創(chuàng)建的表
						transaction.savepoint_rollback(save_id)
						return JsonResponse({'res':4, 'errmsg':'商品不存在'})
					# 獲取商品的數(shù)量
					count = conn.hget(cart_key, sku_id)
					# 校驗庫存值
					if int(count)>sku.stock:
						# 回滾到保存點
						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è)置保存點,因此將判斷放在添加記錄的前面,防止重復(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()
					# 計算訂單商品的總數(shù)量和總價格
					amount = sku.price*int(count)
					total_count += int(count)
					total_price += amount
					break
			# 更新訂單詳情表中的總數(shù)量和總價格
			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)建成功'})			

訂單的顯示

訂單顯示在個人中心中,根據(jù)用戶從訂單模型類中取出所有的訂單實例,再根據(jù)每個訂單實例從訂單商品類中取出對應(yīng)的商品(此處不從sku商品表中取,因為訂單提交時的價格與當(dāng)前價格可能不同),計算小計并動態(tài)添加屬性,然后進行分頁,對分頁對象進行處理。

注:①操作與商品列表分頁類似,對于訂單的排序此處略過,默認按照創(chuàng)建時間進行排序;

②在前端中,根據(jù)用戶訂單的支付狀態(tài)和支付方式確定提供給用戶的按鈕文字,并根據(jù)支付狀態(tài)來判斷點擊時進行的邏輯(去支付/去評論)。

訂單的支付

此處調(diào)用支付寶的測試接口進行支付,關(guān)于支付寶接口的調(diào)用詳情可參支付寶沙箱環(huán)境開發(fā)文檔.

訂單支付結(jié)果的查詢

如上圖所示,支付寶在支付結(jié)果產(chǎn)生后會向網(wǎng)站返回支付結(jié)果,但可能由于網(wǎng)絡(luò)原因并不準確,因此主動去調(diào)用支付寶接口查詢支付狀態(tài),在引導(dǎo)用戶去支付頁面之后就發(fā)起ajax post請求用于獲取支付結(jié)果,循環(huán)調(diào)用支付寶接口進行查詢(此接口的返回值中包括等待用戶付款),若支付成功則更改訂單支付狀態(tài)并返回,若支付失敗則返回錯誤信息。

注:訂單的支付是由用戶與支付寶交互完成的,網(wǎng)站服務(wù)器不參與,網(wǎng)站服務(wù)器只負責(zé)提供支付鏈接與查詢支付結(jié)果,通過支付寶的返回狀態(tài)來對當(dāng)前用戶訂單狀態(tài)進行更改。

商品評論

①評論頁面顯示:當(dāng)訂單支付成功,直接跳轉(zhuǎn)到商品評論頁面,商品評論頁面中單個訂單的多個商品都有自己的評論框,使用form表單的形式進行提交。

注:由于有多個商品,而顯示的時候是循環(huán)顯示,因此使用forloop.counter給商品和評論框起名,這樣可以對它們進行綁定,避免混淆。

②評論內(nèi)容提交:如上所述,在后端中獲取提交的評論內(nèi)容并將其添加到訂單商品類中,更改訂單狀態(tài),訂單完成,重定向到訂單頁面。

注:由于一個訂單中的商品可能有的評價有的不評價,會造成訂單狀態(tài)的不確定,因此可以設(shè)置若不評價則給出默認值或評論框不允許為空,即只要點擊進入評論頁面,無論如何處理只要邏輯完成則更改訂單狀態(tài)為已完成。

關(guān)于django訂單模塊的實現(xiàn)方法就分享到這里了,希望以上內(nèi)容可以對大家有一定的幫助,可以學(xué)到更多知識。如果覺得文章不錯,可以把它分享出去讓更多的人看到。

分享題目:django訂單模塊的實現(xiàn)方法-創(chuàng)新互聯(lián)
網(wǎng)站網(wǎng)址:http://www.muchs.cn/article10/dsjido.html

成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供標(biāo)簽優(yōu)化、面包屑導(dǎo)航動態(tài)網(wǎng)站、企業(yè)網(wǎng)站制作電子商務(wù)、小程序開發(fā)

廣告

聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)

成都網(wǎng)站建設(shè)公司