Django REST framework+Vue 打造生鮮超市(十一)

目錄javascript

生鮮超市(一)    生鮮超市(二)    生鮮超市(三)   html

生鮮超市(四)    生鮮超市(五)    生鮮超市(六)   前端

生鮮超市(七)    生鮮超市(八)    生鮮超市(九)   vue

生鮮超市(十)    生鮮超市(十一)    生鮮超市(十二)    生鮮超市(十三)   java

代碼下載linux

githubgit

教程github

學習自慕課網-前端vue結合後端DjangoFramework的在線生鮮超市 數據庫

12、支付寶沙箱環境配置

12.1.建立應用

進入螞蟻金服開放平臺(https://open.alipay.com/platform/home.htm),登陸後進入管理中心-->>應用列表npm

 建立應用

 

 建立應用後會有一個appid。還須要提交信息進行審覈。微信支付和支付寶支付都是要求企業認證才能夠完成的,我的開發不能夠,因此咱們須要用

沙箱環境,它可讓咱們不具有這些應用或者說應用審覈還沒經過的時候先開發調試

 

12.2.沙箱環境

沙箱應用地址:https://openhome.alipay.com/platform/appDaily.htm?tab=info

 

(1)公鑰和私鑰的生成方法

地址:https://docs.open.alipay.com/291/105971/

選winwods,若是linux就選linux

下載好工具照着生成就能夠了

 

 

 (2) 把生成的公鑰和私鑰拷貝到trade/keys下面--->>>重命名--->>首位各添加下面的內容

-----BEGIN PRIVATE KEY-----
-----END PRIVATE KEY-----

 

 

 

(3)把支付寶公鑰也拷貝到這路徑下面,一樣首尾添加

 

 

 

12.3.文檔說明

咱們主要用到電腦網站支付,文檔地址:https://docs.open.alipay.com/270

用到的API接口:統一收單下單並支付頁面接口

裏面有文檔說明

 

幾個比較重要的參數

 

 

 sign簽名

 應該看未使用開放平臺的SDK裏面的說明:https://docs.open.alipay.com/291/106118

 

 請求參數

必填的幾個:

 

 

12.4.編寫代碼

把環境改爲本地的

首先的安裝一個模塊

pip install pycryptodome

utils中新建alipay.py,代碼以下:

# apps/utils.py

import json
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes


class AliPay(object):
    """
    支付寶支付接口
    """
    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=False):
        self.appid = appid
        self.app_notify_url = app_notify_url
        #私鑰
        self.app_private_key_path = app_private_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())
        #公鑰
        self.alipay_public_key_path = alipay_public_key_path
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.import_key(fp.read())


        if debug is True:
            self.__gateway = "https://openapi.alipaydev.com/gateway.do"
        else:
            self.__gateway = "https://openapi.alipay.com/gateway.do"

    def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
        #請求參數
        biz_content = {
            "subject": subject,
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "product_code": "FAST_INSTANT_TRADE_PAY",
            # "qr_pay_mode":4
        }
        #容許傳遞更多參數,放到biz_content
        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
        return self.sign_data(data)

    def build_body(self, method, biz_content, return_url=None):
        #build_body主要生產消息的格式
        #公共請求參數
        data = {
            "app_id": self.appid,
            "method": method,
            "charset": "utf-8",
            "sign_type": "RSA2",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "version": "1.0",
            "biz_content": biz_content
        }

        if return_url is not None:
            data["notify_url"] = self.app_notify_url
            data["return_url"] = self.return_url

        return data

    def sign_data(self, data):
        #簽名
        data.pop("sign", None)
        # 排序後的字符串
        unsigned_items = self.ordered_data(data)
        #排完序後拼接起來
        unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
        #這裏獲得簽名的字符串
        sign = self.sign(unsigned_string.encode("utf-8"))
        #對url進行處理
        quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

        # 得到最終的訂單信息字符串
        signed_string = quoted_string + "&sign=" + quote_plus(sign)
        return signed_string

    #參數傳進來必定要排序
    def ordered_data(self, data):
        complex_keys = []
        for key, value in data.items():
            if isinstance(value, dict):
                complex_keys.append(key)

        # 將字典類型的數據dump出來
        for key in complex_keys:
            data[key] = json.dumps(data[key], separators=(',', ':'))

        return sorted([(k, v) for k, v in data.items()])

    def sign(self, unsigned_string):
        # 開始計算簽名
        key = self.app_private_key
        #簽名的對象
        signer = PKCS1_v1_5.new(key)
        #生成簽名
        signature = signer.sign(SHA256.new(unsigned_string))
        # base64 編碼,轉換爲unicode表示並移除回車
        sign = encodebytes(signature).decode("utf8").replace("\n", "")
        return sign

    def _verify(self, raw_content, signature):
        # 開始計算簽名
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode("utf8"))
        if signer.verify(digest, decodebytes(signature.encode("utf8"))):
            return True
        return False

    def verify(self, data, signature):
        if "sign_type" in data:
            sign_type = data.pop("sign_type")
        # 排序後的字符串
        unsigned_items = self.ordered_data(data)
        message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
        return self._verify(message, signature)


if __name__ == "__main__":
    return_url = 'http://127.0.0.1:8000/?total_amount=100.00&timestamp=2017-08-15+23%3A53%3A34&sign=e9E9UE0AxR84NK8TP1CicX6aZL8VQj68ylugWGHnM79zA7BKTIuxxkf%2FvhdDYz4XOLzNf9pTJxTDt8tTAAx%2FfUAJln4WAeZbacf1Gp4IzodcqU%2FsIc4z93xlfIZ7OLBoWW0kpKQ8AdOxrWBMXZck%2F1cffy4Ya2dWOYM6Pcdpd94CLNRPlH6kFsMCJCbhqvyJTflxdpVQ9kpH%2B%2Fhpqrqvm678vLwM%2B29LgqsLq0lojFWLe5ZGS1iFBdKiQI6wZiisBff%2BdAKT9Wcao3XeBUGigzUmVyEoVIcWJBH0Q8KTwz6IRC0S74FtfDWTafplUHlL%2Fnf6j%2FQd1y6Wcr2A5Kl6BQ%3D%3D&trade_no=2017081521001004340200204115&sign_type=RSA2&auth_app_id=2016080600180695&charset=utf-8&seller_id=2088102170208070&method=alipay.trade.page.pay.return&app_id=2016080600180695&out_trade_no=20170202185&version=1.0'
    o = urlparse(return_url)
    query = parse_qs(o.query)
    processed_query = {}
    ali_sign = query.pop("sign")[0]


# 測試用例
    alipay = AliPay(
        # 沙箱裏面的appid值
        appid="2016091500517456",
        #notify_url是異步的url
        app_notify_url="http://127.0.0.1:8000/",
        # 咱們本身商戶的密鑰
        app_private_key_path="../trade/keys/private_2048.txt",
        # 支付寶的公鑰
        alipay_public_key_path="../trade/keys/alipay_key_2048.txt",  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
        # debug爲true時使用沙箱的url。若是不是用正式環境的url
        debug=True,  # 默認False,
        return_url="http://127.0.0.1:8000/alipay/return/"
    )

    for key, value in query.items():
        processed_query[key] = value[0]
    # print (alipay.verify(processed_query, ali_sign))

    # 直接支付:生成請求的字符串。
    url = alipay.direct_pay(
        # 訂單標題
        subject="測試訂單derek",
        # 咱們商戶自行生成的訂單號
        out_trade_no="20180417derek",
        # 訂單金額
        total_amount=100,
        #成功付款後跳轉到的頁面,return_url同步的url
        # return_url="http://127.0.0.1:8000/"
    )
    # 將生成的請求字符串拿到咱們的url中進行拼接
    re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

    print(re_url)

 

運行alipay.py,會生成一個支付連接url,點進去跳到支付頁面

 

 點「登陸帳戶付款」,用沙箱帳號付款

 

 輸入帳號密碼以及支付密碼,成功付款

 

 12.5.django集成支付寶notify_url和return_url

(1)配置url

# 配置支付寶支付相關接口的url
path('alipay/return/', AlipayView.as_view())

(2)alipay.py

把return_url和notify_url都改爲遠程服務器的地址

return_url="http://47.93.198.159:8000/alipay/return/"

app_notify_url="http://47.93.198.159:8000/alipay/return/"
# apps/utils.py

import json
from datetime import datetime
from Crypto.PublicKey import RSA
from Crypto.Signature import PKCS1_v1_5
from Crypto.Hash import SHA256
from base64 import b64encode, b64decode
from urllib.parse import quote_plus
from urllib.parse import urlparse, parse_qs
from urllib.request import urlopen
from base64 import decodebytes, encodebytes


class AliPay(object):
    """
    支付寶支付接口
    """
    def __init__(self, appid, app_notify_url, app_private_key_path,
                 alipay_public_key_path, return_url, debug=False):
        self.appid = appid
        self.app_notify_url = app_notify_url
        #私鑰
        self.app_private_key_path = app_private_key_path
        self.app_private_key = None
        self.return_url = return_url
        with open(self.app_private_key_path) as fp:
            self.app_private_key = RSA.importKey(fp.read())
        #公鑰
        self.alipay_public_key_path = alipay_public_key_path
        with open(self.alipay_public_key_path) as fp:
            self.alipay_public_key = RSA.import_key(fp.read())


        if debug is True:
            self.__gateway = "https://openapi.alipaydev.com/gateway.do"
        else:
            self.__gateway = "https://openapi.alipay.com/gateway.do"

    def direct_pay(self, subject, out_trade_no, total_amount, return_url=None, **kwargs):
        #請求參數
        biz_content = {
            "subject": subject,
            "out_trade_no": out_trade_no,
            "total_amount": total_amount,
            "product_code": "FAST_INSTANT_TRADE_PAY",
            # "qr_pay_mode":4
        }
        #容許傳遞更多參數,放到biz_content
        biz_content.update(kwargs)
        data = self.build_body("alipay.trade.page.pay", biz_content, self.return_url)
        return self.sign_data(data)

    def build_body(self, method, biz_content, return_url=None):
        #build_body主要生產消息的格式
        #公共請求參數
        data = {
            "app_id": self.appid,
            "method": method,
            "charset": "utf-8",
            "sign_type": "RSA2",
            "timestamp": datetime.now().strftime("%Y-%m-%d %H:%M:%S"),
            "version": "1.0",
            "biz_content": biz_content
        }

        if return_url is not None:
            data["notify_url"] = self.app_notify_url
            data["return_url"] = self.return_url

        return data

    def sign_data(self, data):
        #簽名
        data.pop("sign", None)
        # 排序後的字符串
        unsigned_items = self.ordered_data(data)
        #排完序後拼接起來
        unsigned_string = "&".join("{0}={1}".format(k, v) for k, v in unsigned_items)
        #這裏獲得簽名的字符串
        sign = self.sign(unsigned_string.encode("utf-8"))
        #對url進行處理
        quoted_string = "&".join("{0}={1}".format(k, quote_plus(v)) for k, v in unsigned_items)

        # 得到最終的訂單信息字符串
        signed_string = quoted_string + "&sign=" + quote_plus(sign)
        return signed_string

    #參數傳進來必定要排序
    def ordered_data(self, data):
        complex_keys = []
        for key, value in data.items():
            if isinstance(value, dict):
                complex_keys.append(key)

        # 將字典類型的數據dump出來
        for key in complex_keys:
            data[key] = json.dumps(data[key], separators=(',', ':'))

        return sorted([(k, v) for k, v in data.items()])

    def sign(self, unsigned_string):
        # 開始計算簽名
        key = self.app_private_key
        #簽名的對象
        signer = PKCS1_v1_5.new(key)
        #生成簽名
        signature = signer.sign(SHA256.new(unsigned_string))
        # base64 編碼,轉換爲unicode表示並移除回車
        sign = encodebytes(signature).decode("utf8").replace("\n", "")
        return sign

    def _verify(self, raw_content, signature):
        # 開始計算簽名
        key = self.alipay_public_key
        signer = PKCS1_v1_5.new(key)
        digest = SHA256.new()
        digest.update(raw_content.encode("utf8"))
        if signer.verify(digest, decodebytes(signature.encode("utf8"))):
            return True
        return False

    def verify(self, data, signature):
        if "sign_type" in data:
            sign_type = data.pop("sign_type")
        # 排序後的字符串
        unsigned_items = self.ordered_data(data)
        message = "&".join(u"{}={}".format(k, v) for k, v in unsigned_items)
        return self._verify(message, signature)


if __name__ == "__main__":
    return_url = 'http://127.0.0.1:8000/?total_amount=100.00&timestamp=2017-08-15+23%3A53%3A34&sign=e9E9UE0AxR84NK8TP1CicX6aZL8VQj68ylugWGHnM79zA7BKTIuxxkf%2FvhdDYz4XOLzNf9pTJxTDt8tTAAx%2FfUAJln4WAeZbacf1Gp4IzodcqU%2FsIc4z93xlfIZ7OLBoWW0kpKQ8AdOxrWBMXZck%2F1cffy4Ya2dWOYM6Pcdpd94CLNRPlH6kFsMCJCbhqvyJTflxdpVQ9kpH%2B%2Fhpqrqvm678vLwM%2B29LgqsLq0lojFWLe5ZGS1iFBdKiQI6wZiisBff%2BdAKT9Wcao3XeBUGigzUmVyEoVIcWJBH0Q8KTwz6IRC0S74FtfDWTafplUHlL%2Fnf6j%2FQd1y6Wcr2A5Kl6BQ%3D%3D&trade_no=2017081521001004340200204115&sign_type=RSA2&auth_app_id=2016080600180695&charset=utf-8&seller_id=2088102170208070&method=alipay.trade.page.pay.return&app_id=2016080600180695&out_trade_no=20170202185&version=1.0'
    o = urlparse(return_url)
    query = parse_qs(o.query)
    processed_query = {}
    ali_sign = query.pop("sign")[0]


# 測試用例
    alipay = AliPay(
        # 沙箱裏面的appid值
        appid="2016091500517456",
        #notify_url是異步的url
        app_notify_url="http://47.93.198.159:8000/alipay/return/",
        # 咱們本身商戶的密鑰
        app_private_key_path="../trade/keys/private_2048.txt",
        # 支付寶的公鑰
        alipay_public_key_path="../trade/keys/alipay_key_2048.txt",  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
        # debug爲true時使用沙箱的url。若是不是用正式環境的url
        debug=True,  # 默認False,
        return_url="http://47.93.198.159:8000/alipay/return/"
    )

    for key, value in query.items():
        processed_query[key] = value[0]
    # print (alipay.verify(processed_query, ali_sign))

    # 直接支付:生成請求的字符串。
    url = alipay.direct_pay(
        # 訂單標題
        subject="測試訂單derek",
        # 咱們商戶自行生成的訂單號
        out_trade_no="20180417derek2",
        # 訂單金額
        total_amount=100,
        #成功付款後跳轉到的頁面,return_url同步的url
        return_url="http://47.93.198.159:8000/alipay/return/"
    )
    # 將生成的請求字符串拿到咱們的url中進行拼接
    re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

    print(re_url)
alipay.py

(3)settings.py

 settings中配置公鑰私鑰路徑

# 支付寶相關的key
private_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/private_2048.txt')
ali_pub_key_path = os.path.join(BASE_DIR, 'apps/trade/keys/alipay_key_2048.txt')

(4)trade/views.py

from datetime import datetime
from utils.alipay import AliPay
from rest_framework.views import APIView
from MxShop.settings import ali_pub_key_path, private_key_path
from rest_framework.response import Response

class AlipayView(APIView):
    def get(self, request):
        """
        處理支付寶的return_url返回
        """
        processed_dict = {}
        # 1. 獲取GET中參數
        for key, value in request.GET.items():
            processed_dict[key] = value
        # 2. 取出sign
        sign = processed_dict.pop("sign", None)

        # 3. 生成ALipay對象
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        verify_re = alipay.verify(processed_dict, sign)

        # 這裏能夠不作操做。由於無論發不發return url。notify url都會修改訂單狀態。
        if verify_re is True:
            order_sn = processed_dict.get('out_trade_no', None)
            trade_no = processed_dict.get('trade_no', None)
            trade_status = processed_dict.get('trade_status', None)

            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
            for existed_order in existed_orders:
                existed_order.pay_status = trade_status
                existed_order.trade_no = trade_no
                existed_order.pay_time = datetime.now()
                existed_order.save()


    def post(self, request):
        """
        處理支付寶的notify_url
        """
        #存放post裏面全部的數據
        processed_dict = {}
        #取出post裏面的數據
        for key, value in request.POST.items():
            processed_dict[key] = value
        #把signpop掉,文檔有說明
        sign = processed_dict.pop("sign", None)

        #生成一個Alipay對象
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        #進行驗證
        verify_re = alipay.verify(processed_dict, sign)

        # 若是驗籤成功
        if verify_re is True:
            #商戶網站惟一訂單號
            order_sn = processed_dict.get('out_trade_no', None)
            #支付寶系統交易流水號
            trade_no = processed_dict.get('trade_no', None)
            #交易狀態
            trade_status = processed_dict.get('trade_status', None)

            # 查詢數據庫中訂單記錄
            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
            for existed_order in existed_orders:
                # 訂單商品項
                order_goods = existed_order.goods.all()
                # 商品銷量增長訂單中數值
                for order_good in order_goods:
                    goods = order_good.goods
                    goods.sold_num += order_good.goods_num
                    goods.save()

                # 更新訂單狀態
                existed_order.pay_status = trade_status
                existed_order.trade_no = trade_no
                existed_order.pay_time = datetime.now()
                existed_order.save()
            #須要返回一個'success'給支付寶,若是不返回,支付寶會一直髮送訂單支付成功的消息
            return Response("success")

 

(5)trade/serializers.py

建立訂單的時候生成一個支付的url,這個邏輯OderSerializer和OrderDetailSerializer中都添加

 #支付訂單的url
    alipay_url = serializers.SerializerMethodField(read_only=True)

    def get_alipay_url(self, obj):
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        url = alipay.direct_pay(
            subject=obj.order_sn,
            out_trade_no=obj.order_sn,
            total_amount=obj.order_mount,
        )
        re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

        return re_url
# trade/serializer.py
__author__ = 'derek'

import time

from .models import ShoppingCart
from rest_framework import serializers
from goods.models import Goods
from goods.serializers import GoodsSerializer
from .models import OrderInfo,OrderGoods
from MxShop.settings import ali_pub_key_path, private_key_path
from utils.alipay import AliPay

class ShopCartDetailSerializer(serializers.ModelSerializer):
    '''
    購物車商品詳情信息
    '''
    # 一個購物車對應一個商品
    goods = GoodsSerializer(many=False, read_only=True)
    class Meta:
        model = ShoppingCart
        fields = ("goods", "nums")


class ShopCartSerializer(serializers.Serializer):
    #獲取當前登陸的用戶
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    nums = serializers.IntegerField(required=True, label="數量",min_value=1,
                                    error_messages={
                                        "min_value":"商品數量不能小於一",
                                        "required": "請選擇購買數量"
                                    })
    #這裏是繼承Serializer,必須指定queryset對象,若是繼承ModelSerializer則不須要指定
    #goods是一個外鍵,能夠經過這方法獲取goods object中全部的值
    goods = serializers.PrimaryKeyRelatedField(required=True, queryset=Goods.objects.all())

    #繼承的Serializer沒有save功能,必須寫一個create方法
    def create(self, validated_data):
        # validated_data是已經處理過的數據
        #獲取當前用戶
        # view中:self.request.user;serizlizer中:self.context["request"].user
        user = self.context["request"].user
        nums = validated_data["nums"]
        goods = validated_data["goods"]

        existed = ShoppingCart.objects.filter(user=user, goods=goods)
        #若是購物車中有記錄,數量+1
        #若是購物車車沒有記錄,就建立
        if existed:
            existed = existed[0]
            existed.nums += nums
            existed.save()
        else:
            #添加到購物車
            existed = ShoppingCart.objects.create(**validated_data)

        return existed

    def update(self, instance, validated_data):
        # 修改商品數量
        instance.nums = validated_data["nums"]
        instance.save()
        return instance


#訂單中的商品
class OrderGoodsSerialzier(serializers.ModelSerializer):
    goods = GoodsSerializer(many=False)
    class Meta:
        model = OrderGoods
        fields = "__all__"

#訂單商品信息
# goods字段須要嵌套一個OrderGoodsSerializer
class OrderDetailSerializer(serializers.ModelSerializer):
    goods = OrderGoodsSerialzier(many=True)
    # 支付訂單的url
    alipay_url = serializers.SerializerMethodField(read_only=True)

    def get_alipay_url(self, obj):
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        url = alipay.direct_pay(
            subject=obj.order_sn,
            out_trade_no=obj.order_sn,
            total_amount=obj.order_mount,
        )
        re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

        return re_url
    class Meta:
        model = OrderInfo
        fields = "__all__"

class OrderSerializer(serializers.ModelSerializer):
    user = serializers.HiddenField(
        default=serializers.CurrentUserDefault()
    )
    #生成訂單的時候這些不用post
    pay_status = serializers.CharField(read_only=True)
    trade_no = serializers.CharField(read_only=True)
    order_sn = serializers.CharField(read_only=True)
    pay_time = serializers.DateTimeField(read_only=True)
    nonce_str = serializers.CharField(read_only=True)
    pay_type = serializers.CharField(read_only=True)
    #支付訂單的url
    alipay_url = serializers.SerializerMethodField(read_only=True)

    def get_alipay_url(self, obj):
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        url = alipay.direct_pay(
            subject=obj.order_sn,
            out_trade_no=obj.order_sn,
            total_amount=obj.order_mount,
        )
        re_url = "https://openapi.alipaydev.com/gateway.do?{data}".format(data=url)

        return re_url


    def generate_order_sn(self):
        #生成訂單號
        # 當前時間+userid+隨機數
        from random import Random
        random_ins = Random()
        order_sn = "{time_str}{userid}{ranstr}".format(time_str=time.strftime("%Y%m%d%H%M%S"),
                                                       userid=self.context["request"].user.id,
                                                       ranstr=random_ins.randint(10, 99))
        return order_sn

    def validate(self, attrs):
        #validate中添加order_sn,而後在view中就能夠save
        attrs["order_sn"] = self.generate_order_sn()
        return attrs

    class Meta:
        model = OrderInfo
        fields = "__all__"
trade/serializer.py

 

(6)測試代碼

把本地修改的地方必定要上傳到服務器,由於咱們須要在服務器上調試代碼

vue項目中api.js裏面local_host改成服務器ip

let local_host = 'http://47.93.198.159:8000';

在phcharm中開始運行項目

瀏覽器訪問地址:http://47.93.198.159:8000/orders/

建立一個訂單

生成訂單的詳情

 

12.6.vue靜態文件放到django中

vue有兩種開發模式

  • build    用來生成靜態文件 
  • dev

(1)運行

cnpm run build

生成的靜態文件在dist目錄下面

 

(2)把index.html拷貝到templates目錄下

(3)django中建立static目錄

  • 把index.entry.js考到django的static目錄下面
  • 把dist/static下的兩個文件夾拷貝到django static目錄下

 

(4)settings設置靜態文件路徑

STATIC_URL = '/static/'
STATICFILES_DIRS = (
    os.path.join(BASE_DIR, "static"),
)

 (5)修改index.html中靜態文件路徑

<script type="text/javascript" src="/static/index.entry.js"></script></body>

(6)配置index的url

from django.views.generic import TemplateView

urlpatterns = [
    # 首頁
    path('index/', TemplateView.as_view(template_name='index.html'),name='index')
]

 (7)配置支付成功return的地址

trade/views.py

 response = redirect("/index/#/app/home/member/order")
            return response

        else:
            response = redirect("index")
            return response
# trade/views.py

from rest_framework import viewsets
from rest_framework.permissions import IsAuthenticated
from utils.permissions import IsOwnerOrReadOnly
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.authentication import SessionAuthentication
from .serializers import ShopCartSerializer,ShopCartDetailSerializer,OrderDetailSerializer,OrderGoodsSerialzier,OrderSerializer
from .models import ShoppingCart,OrderGoods,OrderInfo
from rest_framework import mixins
from django.shortcuts import render, redirect


class ShoppingCartViewset(viewsets.ModelViewSet):
    """
    購物車功能
    list:
        獲取購物車詳情
    create:
        加入購物車
    delete:
        刪除購物記錄
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = ShopCartSerializer
    #商品的id
    lookup_field = "goods_id"

    def get_serializer_class(self):
        if self.action == 'list':
            return ShopCartDetailSerializer
        else:
            return ShopCartSerializer

    #獲取購物車列表
    def get_queryset(self):
        return ShoppingCart.objects.filter(user=self.request.user)


class OrderViewset(mixins.ListModelMixin, mixins.RetrieveModelMixin, mixins.CreateModelMixin, mixins.DestroyModelMixin,
                   viewsets.GenericViewSet):
    """
    訂單管理
    list:
        獲取我的訂單
    delete:
        刪除訂單
    create:
        新增訂單
    """
    permission_classes = (IsAuthenticated, IsOwnerOrReadOnly)
    authentication_classes = (JSONWebTokenAuthentication, SessionAuthentication)
    serializer_class = OrderSerializer
    #動態配置serializer
    def get_serializer_class(self):
        if self.action == "retrieve":
            return OrderDetailSerializer
        return OrderSerializer
    #獲取訂單列表
    def get_queryset(self):
        return OrderInfo.objects.filter(user=self.request.user)

    #在訂單提交保存以前還須要多兩步步驟,因此這裏自定義perform_create方法
    #1.將購物車中的商品保存到OrderGoods中
    #2.狀況購物車
    def perform_create(self, serializer):
        order = serializer.save()
        # 獲取購物車全部商品
        shop_carts = ShoppingCart.objects.filter(user=self.request.user)
        for shop_cart in shop_carts:
            order_goods = OrderGoods()
            order_goods.goods = shop_cart.goods
            order_goods.goods_num = shop_cart.nums
            order_goods.order = order
            order_goods.save()
            #清空購物車
            shop_cart.delete()
        return order

from datetime import datetime
from utils.alipay import AliPay
from rest_framework.views import APIView
from MxShop.settings import ali_pub_key_path, private_key_path
from rest_framework.response import Response

class AlipayView(APIView):
    def get(self, request):
        """
        處理支付寶的return_url返回
        """
        processed_dict = {}
        # 1. 獲取GET中參數
        for key, value in request.GET.items():
            processed_dict[key] = value
        # 2. 取出sign
        sign = processed_dict.pop("sign", None)

        # 3. 生成ALipay對象
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        verify_re = alipay.verify(processed_dict, sign)

        # 這裏能夠不作操做。由於無論發不發return url。notify url都會修改訂單狀態。
        if verify_re is True:
            order_sn = processed_dict.get('out_trade_no', None)
            trade_no = processed_dict.get('trade_no', None)
            trade_status = processed_dict.get('trade_status', None)

            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
            for existed_order in existed_orders:
                existed_order.pay_status = trade_status
                existed_order.trade_no = trade_no
                existed_order.pay_time = datetime.now()
                existed_order.save()

            response = redirect("/index/#/app/home/member/order")
            return response

        else:
            response = redirect("index")
            return response

    def post(self, request):
        """
        處理支付寶的notify_url
        """
        #存放post裏面全部的數據
        processed_dict = {}
        #取出post裏面的數據
        for key, value in request.POST.items():
            processed_dict[key] = value
        #把signpop掉,文檔有說明
        sign = processed_dict.pop("sign", None)

        #生成一個Alipay對象
        alipay = AliPay(
            appid="2016091500517456",
            app_notify_url="http://47.93.198.159:8000/alipay/return/",
            app_private_key_path=private_key_path,
            alipay_public_key_path=ali_pub_key_path,  # 支付寶的公鑰,驗證支付寶回傳消息使用,不是你本身的公鑰,
            debug=True,  # 默認False,
            return_url="http://47.93.198.159:8000/alipay/return/"
        )

        #進行驗證
        verify_re = alipay.verify(processed_dict, sign)

        # 若是驗籤成功
        if verify_re is True:
            #商戶網站惟一訂單號
            order_sn = processed_dict.get('out_trade_no', None)
            #支付寶系統交易流水號
            trade_no = processed_dict.get('trade_no', None)
            #交易狀態
            trade_status = processed_dict.get('trade_status', None)

            # 查詢數據庫中訂單記錄
            existed_orders = OrderInfo.objects.filter(order_sn=order_sn)
            for existed_order in existed_orders:
                # 訂單商品項
                order_goods = existed_order.goods.all()
                # 商品銷量增長訂單中數值
                for order_good in order_goods:
                    goods = order_good.goods
                    goods.sold_num += order_good.goods_num
                    goods.save()

                # 更新訂單狀態
                existed_order.pay_status = trade_status
                existed_order.trade_no = trade_no
                existed_order.pay_time = datetime.now()
                existed_order.save()
            #須要返回一個'success'給支付寶,若是不返回,支付寶會一直髮送訂單支付成功的消息
            return Response("success")
# trade/views.py

 

如今能夠經過index直接訪問了:http://47.93.198.159:8000/index/#/app/home/index

添加商品到購物車-->>去結算-->>生成訂單-->>跳到支付頁面了

相關文章
相關標籤/搜索