欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

django多種支付、并發(fā)訂單處理實例代碼

 更新時間:2019年12月13日 08:38:01   作者:Micheal_L  
在本篇文章里小編給大家整理的是關(guān)于django多種支付、并發(fā)訂單處理實例代碼,需要的朋友們可以學(xué)習(xí)下。

django實現(xiàn)多種支付方式

'''
#思路
  
  我們希望,通過插拔的方式來實現(xiàn)多方式登錄,比如新增一種支付方式,那么只要在項目中新增一個py文件,導(dǎo)入里面的pay方法就可以了,這樣在支付業(yè)務(wù)中支付語句是不發(fā)生變化的。
  所以就可以使用python的鴨子類型及面向?qū)ο蟮姆瓷浞椒▉韺崿F(xiàn)功能

'''

##新建一個Pay文件夾,里面放支付方式.py文件
#Alipay.py
class Alipay:
  def pay(self):
    pass
#Visapay.py
class Visapay:
  def pay(self):
    pass
#Wxpay.py(完全按照接口文檔來得)
import time
#記得導(dǎo)入商戶號和key哦!
from app01.wx import settings
class Wxpay:
  def pay(self,order_data):
    self.order_id = order_data["order_id"]
    self.open_id = order_data['open_id']
    self.ip = order_data['ip']
    data_body = self.get_body_data()
    import requests
    url = "https://api.mch.weixin.qq.com/pay/unifiedorder"
    response = requests.post(url, data_body.encode("utf-8"), headers={'content-type': "application/xml"})
    res_dict = self.xml_to_dic(response.content)
    timeStamp = str(int(time.time()))
    paySign = self.get_pay_sign(res_dict, timeStamp)

    data_dic = {
      'timeStamp': timeStamp,
      'nonceStr': res_dict['nonce_str'],
      'package': f"prepay_id={res_dict['prepay_id']}",
      'signType': 'MD5',
      "paySign": paySign,
    }

    return data_dic

  def get_pay_sign(self, res_dict, timeStamp):
    print("res_dict", res_dict)
    data_dic = {
      'appId': res_dict['appid'],
      'timeStamp': timeStamp,
      'nonceStr': res_dict['nonce_str'],
      'package': f"prepay_id={res_dict['prepay_id']}",
      "signType": "MD5"
    }
    sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
    sign_str = f"{sign_str}&key={settings.pay_apikey}"
    import hashlib
    md5 = hashlib.md5()
    md5.update(sign_str.encode("utf-8"))
    sign = md5.hexdigest()
    return sign.upper()

  def xml_to_dic(self, xml_data):
    import xml.etree.ElementTree as ET
    '''
    xml to dict
    :param xml_data:
    :return:
    '''
    xml_dict = {}
    root = ET.fromstring(xml_data)
    for child in root:
      xml_dict[child.tag] = child.text
    return xml_dict

  def get_random(self):
    import random
    data = "123456789zxcvbnmasdfghjklqwertyuiopZXCVBNMASDFGHJKLQWERTYUIOP"
    nonce_str = "".join(random.sample(data, 30))
    return nonce_str



  def get_sign(self):
    data_dic = {
      "nonce_str": self.nonce_str,
      "out_trade_no": self.out_trade_no,
      "spbill_create_ip": self.spbill_create_ip,
      "notify_url": self.notify_url,
      "openid": self.open_id,
      "body": self.body,
      "trade_type": "JSAPI",
      "appid": self.appid,
      "total_fee": "1",
      "mch_id": self.mch_id
    }

    sign_str = "&".join([f"{k}={data_dic[k]}" for k in sorted(data_dic)])
    sign_str = f"{sign_str}&key={settings.pay_apikey}"
    import hashlib
    md5 = hashlib.md5()
    md5.update(sign_str.encode("utf-8"))
    sign = md5.hexdigest()
    return sign.upper()

  def get_body_data(self):
    self.appid = settings.AppId
    # openid=self.open_id
    self.mch_id = str(settings.pay_mchid)
    self.nonce_str = self.get_random()
    self.out_trade_no = self.order_id
    self.spbill_create_ip = self.ip
    self.notify_url = "https://www.test.com"
    self.body = "老男孩學(xué)費"
    self.sign = self.get_sign()
    body_data = f"""
      <xml>
        <appid>{self.appid}</appid>
        <mch_id>{self.mch_id}</mch_id>
        <nonce_str>{self.nonce_str}</nonce_str>
        <sign>{self.sign}</sign>
        <body>{self.body}</body>
        <out_trade_no>{self.out_trade_no}</out_trade_no>
        <total_fee>1</total_fee>
        <spbill_create_ip>{ self.spbill_create_ip}</spbill_create_ip>
        <notify_url>{self.notify_url}</notify_url>
        <openid>{self.open_id}</openid>
        <trade_type>JSAPI</trade_type> 
      </xml>"""
    return body_data
  
  
  
##調(diào)用支付方法的語句(一般支付都是發(fā)生在訂單創(chuàng)建好之后)
import importlib
from rest_framework.response import Response
pay_method = "Wxpay" #這里是舉例子,所以把pay_method寫死了,正常情況下,應(yīng)該是外面?zhèn)鱽淼闹Ц斗绞?,然后用pay_method接收
try:
  #用字符串導(dǎo)入支付方式的py文件,例如這里的app01.Pay.{pay_method}
  pay_field = importlib.import_module(f"app01.Pay.{pay_method}")
  
  #用反射拿到該文件下面的類
  pay_method_class = getattr(pay_field, pay_method)
except:
  return Response({"code": 205, "msg": "錯誤的支付方式"})

order_data['ip'] = host_ip
order_data['open_id'] = open_id

#完成支付,并把支付數(shù)據(jù)返回
pay_data = pay_method_class().pay(order_data)
'''
這里直接用反射拿到的支付類,然后使用它的pay方法,完成支付
'''
return Response({"code": 200, "msg": "ok", "data": pay_data})

django實現(xiàn)訂單創(chuàng)建及支付

'''
幾個注意點:
  1.a,b兩個用戶同時買一個庫存為1的商品,這樣為了保證數(shù)據(jù)安全(即a買了,庫存沒更新,b又買了,這樣就存在安全問題),需要在數(shù)據(jù)庫操作時加鎖,有兩個選擇:悲觀鎖和樂觀鎖。
  悲觀鎖:沖突比較多的時候,使用悲觀鎖。悲觀鎖獲取數(shù)據(jù)時對數(shù)據(jù)行了鎖定,其他事務(wù)要想獲取鎖,必須等原事務(wù)結(jié)束。
  樂觀鎖:沖突比較少的時候,使用樂觀鎖。查詢時不鎖數(shù)據(jù),提交更改時進行判斷.使用樂觀鎖前,要先 設(shè)置mysql事務(wù)的隔離級別transaction-isolation = READ-COMMITTED
  2.a用戶的訂單有兩種商品,這樣提交訂單后,假如第一種成功,第二種失敗,很顯然在訂單一個函數(shù)里面寫一個邏輯是行不通的,應(yīng)該要么同時成功,要么同時失敗。于是自然而然就用到了事務(wù)。
'''
#urls.py
from django.urls import path
from app01.view import order
urlpattern = [
  path('order/create', order.Create.as_view()),
]


#common文件夾下的func.py文件
import time,random
def get_order_id():
  str_all="1242356796734534"
  return time.strftime("%Y%m%d%H%M%S")+"".join(random.sample(str_all,5))


#view文件夾下的order.py文件
from rest_framework.views import APIView
from rest_framework.response import Response
from django.db import transaction
from django import forms
from django.core.cache import cache
from common import func

class OrderForm():
  phone = forms.CharField(
    error_message = {
      'required': "手機號不能為空"
    },
       # 調(diào)用Form組件中的驗證器來校驗手機號
    # validators=[RegexValidator(r'1[1-9][0-9]{9}', '手機號格式不正確')], 
  )
  
    token = forms.CharField( error_messages={
      "required": "token不能為空"
    })
  province=forms.CharField( error_messages={
      "required": "省份不能為空"
    })
  city = forms.CharField(error_messages={
    "required": "城市不能為空"
  })
  county = forms.CharField(error_messages={
    "required": "縣/區(qū)不能為空"
  })
  address = forms.CharField(error_messages={
    "required": "詳細地址不能為空"
  })
  name = forms.CharField(error_messages={
    "required": "姓名不能為空"
  })
  
  
  
  
class Create(APIView):
  @transaction.atomic
  def post(self, requset):
    param = request.data
    #form表單檢驗訂單數(shù)據(jù)是否符合規(guī)范
    for_obj = OrderForm(param)
    #校驗成功,并且買東西了
    if for_obj.is_valid() and param.get('buy_list'):
       buy_list = param.get("buy_list")
        #固定方法拿到付款用戶的id
        if request.META.get("HTTP_X_FORWARDED_FOR"):
          host_ip = request.META["HTTP_X_FROWARDED_FOR"]
        else:
          host_ip = request.META["REMOTE_ADDR"]
        #校驗token,保證登入狀態(tài)
        cache_data = cache.get(param["token"])
        if not cache_data:
          return Response({"code": 202, "msg": "錯誤的token"})
        openid = cache_data.split("&")[0]
        #通過openid查找用戶
        user_data = models.Wxuser.objects.filter(openid=openid).first()
        
        #組織部分總訂單數(shù)據(jù)
      
        order_data = {"consignee_mobile": param['phone'],
               'consignee_name': param['name'],
               'wxuser_id': user_data.id,
               "memo": param['remark'],
               "consignee_area": f"{param['province']},{param['city']},{param['county']}",
               "consignee_address": param['address'],
               }
        
        order_data['order_id']=func.get_order_id()
        order_data["order_total"]=0
        
        
        #獲取用戶購買商品的id
        all_product_id=list(buy_list.keys())
        #通過id來獲取商品的信息
        product_data=models.Product.objects.filter(product_id__in=all_product_id).all()
        
        
        #開啟事務(wù)
 sid = transaction.savepoint()
        for product in product_data:
          product.product_id=str(product.product_id)
          # num=buy_list[product.id]
          #獲取商品的庫存
          for i in range(3):
            product_stock = product.stock.quantity
            new_product_stock = product_stock-buy_list[product.product_id]
            if new_product_stock<0:
              transaction.savepoint_rollback(sid)
              return Response({"code": 204, "msg": f"{product.name}庫存不足"})
            #樂觀鎖
            res=models.Stock.objects.filter(quantity=product_stock,stock_id=product.stock.stock_id).update(quantity=new_product_stock)
            if not res :
              #如果兩次都不成功,就讓用戶重新下單
              if i==2:
                transaction.savepoint_rollback(sid)
                return Response({"code": 205, "msg": "下單失敗從新下單"})
              else:
                continue
            else:
              break

          #組織子訂單數(shù)據(jù)
          order_item_data = {'order_id': order_data['order_id'], 'product_id': product.product_id,"name": product.name, "image": product.image, "price": product.price,
                    "nums": buy_list[product.product_id], "brief": product.brief}
          #創(chuàng)建數(shù)據(jù)
          models.Order_items.objects.create(**order_item_data)

          #獲取訂單總金額
          order_data["order_total"] += buy_list[product.product_id]*product.price

        #創(chuàng)建總訂單
        models.Order.objects.create(**order_data)

        transaction.savepoint_commit(sid)

        #提交延時任務(wù),判斷訂單再指定時間內(nèi),有沒有支付,如果沒有支付,回滾庫存,取消訂單
        func.check_order(order_data['order_id'])

        #如果pay_methon是外面?zhèn)鞯?
        pay_methon= "Wxpay"
        try:
          #導(dǎo)入app01.Pay.{pay_methon}
          pay_filed=importlib.import_module(f"app01.Pay.{pay_methon}")

          #用反射獲取,這個文件中的類
          pay_methon_class=getattr(pay_filed,pay_methon)
        except:
          return Response({"code": 205, "msg": "錯誤的支付方式"})

        order_data['ip'] = host_ip
        order_data['open_id'] = openid

        #獲取小程序所需的支付數(shù)據(jù)
        pay_data= pay_methon_class().pay(order_data)

        # pay_methon ="Alipay"
        # if pay_methon=="Wxpay":
        #   Wxpay().pay
        # elif:...
        # pay_methon
        return Response({"code": 200, "msg": "ok","data":pay_data})
    else:
      return Response({"code": 203, "msg": "缺少參數(shù)"})
    
    
class Notify(APIView):
  def post(self,request,paymethon):
    pay_filed = importlib.import_module(f"app01.Pay.{paymethon}")
    pay_methon_class = getattr(pay_filed, paymethon)
    data=pay_methon_class().notify(request.data)
    if data['stauts']=="suc":
      models.Order.objects.filter(order_id=data['order_id']).update(pay_status="")

celery實現(xiàn)庫存回滾

#proj_celery文件夾下的celery.py文件
import celery
import time

# broker='redis://127.0.0.1:6379/2' 不加密碼
backend = 'redis://127.0.0.1:6379/1'
broker = 'redis://127.0.0.1:6379/2'
cel = celery.Celery('test', backend=backend, broker=broker)

import os, sys
import django

BASE_DIR = os.path.dirname(os.path.dirname(__file__)) # 定位到你的django根目錄
# sys.path.append(os.path.join(BASE_DIR, "app01"))
sys.path.append(os.path.abspath(BASE_DIR))
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "shop.settings")
django.setup()
from django.db import transaction


@cel.task
@transaction.atomic
def del_order(order_id):

  from app01 import models

  # 查看訂單數(shù)據(jù)
  order_data = models.Order.objects.filter(order_id=order_id, pay_status=False).first()

  # 如果有數(shù)據(jù)表示沒有支付,要進行庫存回滾,和取消訂單
  if order_data:

    # 獲取該訂單下的所有子訂單
    order_items = models.Order_items.objects.filter(order_id=order_id).all()

    # 將子訂單中的數(shù)據(jù)轉(zhuǎn)變成 {商品id:購買數(shù)量,。。。}的格式
    product_all_dic = {item.product_id: item.nums for item in order_items}

    # 獲取所有商品的id,成為list格式
    product_all_id = list(product_all_dic.keys())

    # 獲取所有的商品
    all_product = models.Product.objects.filter(product_id__in=product_all_id).all()

    sid = transaction.savepoint()

    # 把對應(yīng)的商品進行庫存回滾
    for product in all_product:
      for i in range(3):
        stock = product.stock.quantity
        new_stock = stock + product_all_dic[product.product_id]

        #樂觀鎖
        res = models.Stock.objects.filter(stock_id=product.stock.stock_id, quantity=stock).update(
          quantity=new_stock)

        if not res:
          if i == 2:
            transaction.savepoint_rollback(sid)

            # 如果這個執(zhí)行失敗了,那我們要從新提交任務(wù),不然庫存無法回滾
            from app01.common import func
            func.check_order(order_id, 1)
            return
          else:
            continue
        else:
          break
    # 修改訂單狀態(tài)
    res1 = models.Order.objects.filter(order_id=order_id, pay_status=False).update(status="dead")
    if res1:
      transaction.savepoint_commit(sid)
    else:
      transaction.savepoint_rollback(sid)

悲觀鎖和樂觀鎖

悲觀鎖和樂觀鎖與并發(fā)訂單處理

以上就是本次介紹的全部相關(guān)知識點,感謝大家的學(xué)習(xí)和對腳本之家的支持。

相關(guān)文章

  • 將pytorch的網(wǎng)絡(luò)等轉(zhuǎn)移到cuda

    將pytorch的網(wǎng)絡(luò)等轉(zhuǎn)移到cuda

    這篇文章主要介紹了將pytorch的網(wǎng)絡(luò)等轉(zhuǎn)移到cuda的實現(xiàn),具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-06-06
  • python學(xué)生管理系統(tǒng)學(xué)習(xí)筆記

    python學(xué)生管理系統(tǒng)學(xué)習(xí)筆記

    這篇文章主要為大家詳細介紹了python學(xué)生管理系統(tǒng)的學(xué)習(xí)筆記,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • python實現(xiàn)登錄與注冊系統(tǒng)

    python實現(xiàn)登錄與注冊系統(tǒng)

    這篇文章主要為大家詳細介紹了python實現(xiàn)登錄與注冊系統(tǒng),文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-11-11
  • python3編碼問題匯總

    python3編碼問題匯總

    本文給通過一個具體的編碼問題的解決辦法,給大家詳細分享了python中的編碼問題的來龍去脈,非常的細致全面,有需要的小伙伴可以參考下
    2016-09-09
  • Python Charles抓包配置實現(xiàn)流程圖解

    Python Charles抓包配置實現(xiàn)流程圖解

    這篇文章主要介紹了Python Charles抓包實現(xiàn)流程圖解,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-09-09
  • 簡單的連接MySQL與Python的Bottle框架的方法

    簡單的連接MySQL與Python的Bottle框架的方法

    這篇文章主要介紹了簡單的連接MySQL與Python的Bottle框架的方法,主要基于mysql-connector插件,需要的朋友可以參考下
    2015-04-04
  • 一文詳解Python中l(wèi)ogging模塊的用法

    一文詳解Python中l(wèi)ogging模塊的用法

    logging是Python標準庫中記錄常用的記錄日志庫,主要用于輸出運行日志,可以設(shè)置輸出日志的等級、日志保存路徑、日志文件回滾等。本文主要來和大家聊聊它的具體用法,希望對大家有所幫助
    2023-02-02
  • Ubuntu16.04安裝python3.6.5步驟詳解

    Ubuntu16.04安裝python3.6.5步驟詳解

    這篇文章主要介紹了Ubuntu16.04安裝python3.6.5詳細步驟,本文給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2020-01-01
  • 基于梯度爆炸的解決方法:clip gradient

    基于梯度爆炸的解決方法:clip gradient

    今天小編就為大家分享一篇基于梯度爆炸的解決方法:clip gradient,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-02-02
  • Python使用re模塊驗證危險字符

    Python使用re模塊驗證危險字符

    這篇文章主要介紹了如何基于python驗證危險字符,文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下
    2020-05-05

最新評論